Fix line endings. WHAMMY.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,326 +1,326 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// NetAdr.cpp: implementation of the CNetAdr class.
|
||||
//
|
||||
//===========================================================================//
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "netadr.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock.h>
|
||||
typedef int socklen_t;
|
||||
#elif !defined( _X360 )
|
||||
#include <netinet/in.h> // ntohs()
|
||||
#include <netdb.h> // gethostbyname()
|
||||
#include <sys/socket.h> // getsockname()
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool netadr_t::CompareAdr (const netadr_t &a, bool onlyBase) const
|
||||
{
|
||||
if ( a.type != type )
|
||||
return false;
|
||||
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_BROADCAST )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if ( !onlyBase && (port != a.port) )
|
||||
return false;
|
||||
|
||||
if ( a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] && a.ip[3] == ip[3] )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool netadr_t::CompareClassBAdr (const netadr_t &a) const
|
||||
{
|
||||
if ( a.type != type )
|
||||
return false;
|
||||
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool netadr_t::CompareClassCAdr (const netadr_t &a) const
|
||||
{
|
||||
if ( a.type != type )
|
||||
return false;
|
||||
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// reserved addresses are not routeable, so they can all be used in a LAN game
|
||||
bool netadr_t::IsReservedAdr () const
|
||||
{
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if ( (ip[0] == 10) || // 10.x.x.x is reserved
|
||||
(ip[0] == 127) || // 127.x.x.x
|
||||
(ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) || // 172.16.x.x - 172.31.x.x
|
||||
(ip[0] == 192 && ip[1] >= 168) ) // 192.168.x.x
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * netadr_t::ToString(bool baseOnly) const
|
||||
{
|
||||
static char s[64];
|
||||
|
||||
Q_strncpy (s, "unknown", sizeof( s ) );
|
||||
|
||||
if (type == NA_LOOPBACK)
|
||||
{
|
||||
Q_strncpy (s, "loopback", sizeof( s ) );
|
||||
}
|
||||
else if (type == NA_BROADCAST)
|
||||
{
|
||||
Q_strncpy (s, "broadcast", sizeof( s ) );
|
||||
}
|
||||
else if (type == NA_IP)
|
||||
{
|
||||
if ( baseOnly)
|
||||
{
|
||||
Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i:%i", ip[0], ip[1], ip[2], ip[3], ntohs(port));
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool netadr_t::IsLocalhost() const
|
||||
{
|
||||
// are we 127.0.0.1 ?
|
||||
return (ip[0] == 127) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 1);
|
||||
}
|
||||
|
||||
bool netadr_t::IsLoopback() const
|
||||
{
|
||||
// are we useding engine loopback buffers
|
||||
return type == NA_LOOPBACK;
|
||||
}
|
||||
|
||||
void netadr_t::Clear()
|
||||
{
|
||||
ip[0] = ip[1] = ip[2] = ip[3] = 0;
|
||||
port = 0;
|
||||
type = NA_NULL;
|
||||
}
|
||||
|
||||
void netadr_t::SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4)
|
||||
{
|
||||
ip[0] = b1;
|
||||
ip[1] = b2;
|
||||
ip[2] = b3;
|
||||
ip[3] = b4;
|
||||
}
|
||||
|
||||
void netadr_t::SetIP(uint unIP)
|
||||
{
|
||||
*((uint*)ip) = BigLong( unIP );
|
||||
}
|
||||
|
||||
void netadr_t::SetType(netadrtype_t newtype)
|
||||
{
|
||||
type = newtype;
|
||||
}
|
||||
|
||||
netadrtype_t netadr_t::GetType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
unsigned short netadr_t::GetPort() const
|
||||
{
|
||||
return BigShort( port );
|
||||
}
|
||||
|
||||
unsigned int netadr_t::GetIPNetworkByteOrder() const
|
||||
{
|
||||
return *(unsigned int *)&ip;
|
||||
}
|
||||
|
||||
unsigned int netadr_t::GetIPHostByteOrder() const
|
||||
{
|
||||
return ntohl( GetIPNetworkByteOrder() );
|
||||
}
|
||||
|
||||
|
||||
void netadr_t::ToSockadr (struct sockaddr * s) const
|
||||
{
|
||||
Q_memset ( s, 0, sizeof(struct sockaddr));
|
||||
|
||||
if (type == NA_BROADCAST)
|
||||
{
|
||||
((struct sockaddr_in*)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)s)->sin_port = port;
|
||||
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else if (type == NA_IP)
|
||||
{
|
||||
((struct sockaddr_in*)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)s)->sin_addr.s_addr = *(int *)&ip;
|
||||
((struct sockaddr_in*)s)->sin_port = port;
|
||||
}
|
||||
else if (type == NA_LOOPBACK )
|
||||
{
|
||||
((struct sockaddr_in*)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)s)->sin_port = port;
|
||||
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_LOOPBACK ;
|
||||
}
|
||||
}
|
||||
|
||||
bool netadr_t::SetFromSockadr(const struct sockaddr * s)
|
||||
{
|
||||
if (s->sa_family == AF_INET)
|
||||
{
|
||||
type = NA_IP;
|
||||
*(int *)&ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
|
||||
port = ((struct sockaddr_in *)s)->sin_port;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool netadr_t::IsValid() const
|
||||
{
|
||||
return ( (port !=0 ) && (type != NA_NULL) &&
|
||||
( ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0 ) );
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef SetPort // get around stupid WINSPOOL.H macro
|
||||
#endif
|
||||
|
||||
void netadr_t::SetPort(unsigned short newport)
|
||||
{
|
||||
port = BigShort( newport );
|
||||
}
|
||||
|
||||
void netadr_t::SetFromString( const char *pch, bool bUseDNS )
|
||||
{
|
||||
Clear();
|
||||
type = NA_IP;
|
||||
|
||||
Assert( pch ); // invalid to call this with NULL pointer; fix your code bug!
|
||||
if ( !pch ) // but let's not crash
|
||||
return;
|
||||
|
||||
|
||||
if ( pch[0] >= '0' && pch[0] <= '9' && strchr( pch, '.' ) )
|
||||
{
|
||||
int n1 = 0, n2 = 0, n3 = 0, n4 = 0, n5 = 0;
|
||||
int nRes = sscanf( pch, "%d.%d.%d.%d:%d", &n1, &n2, &n3, &n4, &n5 );
|
||||
if ( nRes >= 4 )
|
||||
{
|
||||
SetIP( n1, n2, n3, n4 );
|
||||
}
|
||||
|
||||
if ( nRes == 5 )
|
||||
{
|
||||
SetPort( ( uint16 ) n5 );
|
||||
}
|
||||
}
|
||||
else if ( bUseDNS )
|
||||
{
|
||||
// X360TBD:
|
||||
#if !defined( _X360 )
|
||||
char szHostName[ 256 ];
|
||||
Q_strncpy( szHostName, pch, sizeof(szHostName) );
|
||||
char *pchColon = strchr( szHostName, ':' );
|
||||
if ( pchColon )
|
||||
{
|
||||
*pchColon = 0;
|
||||
}
|
||||
|
||||
// DNS it
|
||||
struct hostent *h = gethostbyname( szHostName );
|
||||
if ( !h )
|
||||
return;
|
||||
|
||||
SetIP( ntohl( *(int *)h->h_addr_list[0] ) );
|
||||
|
||||
if ( pchColon )
|
||||
{
|
||||
SetPort( atoi( ++pchColon ) );
|
||||
}
|
||||
#else
|
||||
Assert( 0 );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool netadr_t::operator<(const netadr_t &netadr) const
|
||||
{
|
||||
if ( *((uint *)netadr.ip) < *((uint *)ip) )
|
||||
return true;
|
||||
else if ( *((uint *)netadr.ip) > *((uint *)ip) )
|
||||
return false;
|
||||
return ( netadr.port < port );
|
||||
}
|
||||
|
||||
|
||||
void netadr_t::SetFromSocket( int hSocket )
|
||||
{
|
||||
#if !defined(_X360)
|
||||
Clear();
|
||||
type = NA_IP;
|
||||
|
||||
struct sockaddr address;
|
||||
int namelen = sizeof(address);
|
||||
if ( getsockname( hSocket, (struct sockaddr *)&address, (socklen_t *)&namelen) == 0 )
|
||||
{
|
||||
SetFromSockadr( &address );
|
||||
}
|
||||
#else
|
||||
Assert(0);
|
||||
#endif
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// NetAdr.cpp: implementation of the CNetAdr class.
|
||||
//
|
||||
//===========================================================================//
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "netadr.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock.h>
|
||||
typedef int socklen_t;
|
||||
#elif !defined( _X360 )
|
||||
#include <netinet/in.h> // ntohs()
|
||||
#include <netdb.h> // gethostbyname()
|
||||
#include <sys/socket.h> // getsockname()
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool netadr_t::CompareAdr (const netadr_t &a, bool onlyBase) const
|
||||
{
|
||||
if ( a.type != type )
|
||||
return false;
|
||||
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_BROADCAST )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if ( !onlyBase && (port != a.port) )
|
||||
return false;
|
||||
|
||||
if ( a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] && a.ip[3] == ip[3] )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool netadr_t::CompareClassBAdr (const netadr_t &a) const
|
||||
{
|
||||
if ( a.type != type )
|
||||
return false;
|
||||
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool netadr_t::CompareClassCAdr (const netadr_t &a) const
|
||||
{
|
||||
if ( a.type != type )
|
||||
return false;
|
||||
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if (a.ip[0] == ip[0] && a.ip[1] == ip[1] && a.ip[2] == ip[2] )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// reserved addresses are not routeable, so they can all be used in a LAN game
|
||||
bool netadr_t::IsReservedAdr () const
|
||||
{
|
||||
if ( type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if ( type == NA_IP )
|
||||
{
|
||||
if ( (ip[0] == 10) || // 10.x.x.x is reserved
|
||||
(ip[0] == 127) || // 127.x.x.x
|
||||
(ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31) || // 172.16.x.x - 172.31.x.x
|
||||
(ip[0] == 192 && ip[1] >= 168) ) // 192.168.x.x
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * netadr_t::ToString(bool baseOnly) const
|
||||
{
|
||||
static char s[64];
|
||||
|
||||
Q_strncpy (s, "unknown", sizeof( s ) );
|
||||
|
||||
if (type == NA_LOOPBACK)
|
||||
{
|
||||
Q_strncpy (s, "loopback", sizeof( s ) );
|
||||
}
|
||||
else if (type == NA_BROADCAST)
|
||||
{
|
||||
Q_strncpy (s, "broadcast", sizeof( s ) );
|
||||
}
|
||||
else if (type == NA_IP)
|
||||
{
|
||||
if ( baseOnly)
|
||||
{
|
||||
Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintf (s, sizeof( s ), "%i.%i.%i.%i:%i", ip[0], ip[1], ip[2], ip[3], ntohs(port));
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool netadr_t::IsLocalhost() const
|
||||
{
|
||||
// are we 127.0.0.1 ?
|
||||
return (ip[0] == 127) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 1);
|
||||
}
|
||||
|
||||
bool netadr_t::IsLoopback() const
|
||||
{
|
||||
// are we useding engine loopback buffers
|
||||
return type == NA_LOOPBACK;
|
||||
}
|
||||
|
||||
void netadr_t::Clear()
|
||||
{
|
||||
ip[0] = ip[1] = ip[2] = ip[3] = 0;
|
||||
port = 0;
|
||||
type = NA_NULL;
|
||||
}
|
||||
|
||||
void netadr_t::SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4)
|
||||
{
|
||||
ip[0] = b1;
|
||||
ip[1] = b2;
|
||||
ip[2] = b3;
|
||||
ip[3] = b4;
|
||||
}
|
||||
|
||||
void netadr_t::SetIP(uint unIP)
|
||||
{
|
||||
*((uint*)ip) = BigLong( unIP );
|
||||
}
|
||||
|
||||
void netadr_t::SetType(netadrtype_t newtype)
|
||||
{
|
||||
type = newtype;
|
||||
}
|
||||
|
||||
netadrtype_t netadr_t::GetType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
unsigned short netadr_t::GetPort() const
|
||||
{
|
||||
return BigShort( port );
|
||||
}
|
||||
|
||||
unsigned int netadr_t::GetIPNetworkByteOrder() const
|
||||
{
|
||||
return *(unsigned int *)&ip;
|
||||
}
|
||||
|
||||
unsigned int netadr_t::GetIPHostByteOrder() const
|
||||
{
|
||||
return ntohl( GetIPNetworkByteOrder() );
|
||||
}
|
||||
|
||||
|
||||
void netadr_t::ToSockadr (struct sockaddr * s) const
|
||||
{
|
||||
Q_memset ( s, 0, sizeof(struct sockaddr));
|
||||
|
||||
if (type == NA_BROADCAST)
|
||||
{
|
||||
((struct sockaddr_in*)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)s)->sin_port = port;
|
||||
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else if (type == NA_IP)
|
||||
{
|
||||
((struct sockaddr_in*)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)s)->sin_addr.s_addr = *(int *)&ip;
|
||||
((struct sockaddr_in*)s)->sin_port = port;
|
||||
}
|
||||
else if (type == NA_LOOPBACK )
|
||||
{
|
||||
((struct sockaddr_in*)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in*)s)->sin_port = port;
|
||||
((struct sockaddr_in*)s)->sin_addr.s_addr = INADDR_LOOPBACK ;
|
||||
}
|
||||
}
|
||||
|
||||
bool netadr_t::SetFromSockadr(const struct sockaddr * s)
|
||||
{
|
||||
if (s->sa_family == AF_INET)
|
||||
{
|
||||
type = NA_IP;
|
||||
*(int *)&ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
|
||||
port = ((struct sockaddr_in *)s)->sin_port;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool netadr_t::IsValid() const
|
||||
{
|
||||
return ( (port !=0 ) && (type != NA_NULL) &&
|
||||
( ip[0] != 0 || ip[1] != 0 || ip[2] != 0 || ip[3] != 0 ) );
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef SetPort // get around stupid WINSPOOL.H macro
|
||||
#endif
|
||||
|
||||
void netadr_t::SetPort(unsigned short newport)
|
||||
{
|
||||
port = BigShort( newport );
|
||||
}
|
||||
|
||||
void netadr_t::SetFromString( const char *pch, bool bUseDNS )
|
||||
{
|
||||
Clear();
|
||||
type = NA_IP;
|
||||
|
||||
Assert( pch ); // invalid to call this with NULL pointer; fix your code bug!
|
||||
if ( !pch ) // but let's not crash
|
||||
return;
|
||||
|
||||
|
||||
if ( pch[0] >= '0' && pch[0] <= '9' && strchr( pch, '.' ) )
|
||||
{
|
||||
int n1 = 0, n2 = 0, n3 = 0, n4 = 0, n5 = 0;
|
||||
int nRes = sscanf( pch, "%d.%d.%d.%d:%d", &n1, &n2, &n3, &n4, &n5 );
|
||||
if ( nRes >= 4 )
|
||||
{
|
||||
SetIP( n1, n2, n3, n4 );
|
||||
}
|
||||
|
||||
if ( nRes == 5 )
|
||||
{
|
||||
SetPort( ( uint16 ) n5 );
|
||||
}
|
||||
}
|
||||
else if ( bUseDNS )
|
||||
{
|
||||
// X360TBD:
|
||||
#if !defined( _X360 )
|
||||
char szHostName[ 256 ];
|
||||
Q_strncpy( szHostName, pch, sizeof(szHostName) );
|
||||
char *pchColon = strchr( szHostName, ':' );
|
||||
if ( pchColon )
|
||||
{
|
||||
*pchColon = 0;
|
||||
}
|
||||
|
||||
// DNS it
|
||||
struct hostent *h = gethostbyname( szHostName );
|
||||
if ( !h )
|
||||
return;
|
||||
|
||||
SetIP( ntohl( *(int *)h->h_addr_list[0] ) );
|
||||
|
||||
if ( pchColon )
|
||||
{
|
||||
SetPort( atoi( ++pchColon ) );
|
||||
}
|
||||
#else
|
||||
Assert( 0 );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool netadr_t::operator<(const netadr_t &netadr) const
|
||||
{
|
||||
if ( *((uint *)netadr.ip) < *((uint *)ip) )
|
||||
return true;
|
||||
else if ( *((uint *)netadr.ip) > *((uint *)ip) )
|
||||
return false;
|
||||
return ( netadr.port < port );
|
||||
}
|
||||
|
||||
|
||||
void netadr_t::SetFromSocket( int hSocket )
|
||||
{
|
||||
#if !defined(_X360)
|
||||
Clear();
|
||||
type = NA_IP;
|
||||
|
||||
struct sockaddr address;
|
||||
int namelen = sizeof(address);
|
||||
if ( getsockname( hSocket, (struct sockaddr *)&address, (socklen_t *)&namelen) == 0 )
|
||||
{
|
||||
SetFromSockadr( &address );
|
||||
}
|
||||
#else
|
||||
Assert(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,90 +1,90 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Low level byte swapping routines.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#include "byteswap.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copy a single field from the input buffer to the output buffer, swapping the bytes if necessary
|
||||
//-----------------------------------------------------------------------------
|
||||
void CByteswap::SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField )
|
||||
{
|
||||
switch ( pField->fieldType )
|
||||
{
|
||||
case FIELD_CHARACTER:
|
||||
SwapBufferToTargetEndian<char>( (char*)pOutputBuffer, (char*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_BOOLEAN:
|
||||
SwapBufferToTargetEndian<bool>( (bool*)pOutputBuffer, (bool*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_SHORT:
|
||||
SwapBufferToTargetEndian<short>( (short*)pOutputBuffer, (short*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_FLOAT:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_INTEGER:
|
||||
SwapBufferToTargetEndian<int>( (int*)pOutputBuffer, (int*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_VECTOR:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 3 );
|
||||
break;
|
||||
|
||||
case FIELD_VECTOR2D:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 2 );
|
||||
break;
|
||||
|
||||
case FIELD_QUATERNION:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 4 );
|
||||
break;
|
||||
|
||||
case FIELD_EMBEDDED:
|
||||
{
|
||||
typedescription_t *pEmbed = pField->td->dataDesc;
|
||||
for ( int i = 0; i < pField->fieldSize; ++i )
|
||||
{
|
||||
SwapFieldsToTargetEndian( (byte*)pOutputBuffer + pEmbed->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
(byte*)pData + pEmbed->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
pField->td );
|
||||
|
||||
pOutputBuffer = (byte*)pOutputBuffer + pField->fieldSizeInBytes;
|
||||
pData = (byte*)pData + pField->fieldSizeInBytes;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Write a block of fields. Works a bit like the saverestore code.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CByteswap::SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap )
|
||||
{
|
||||
// deal with base class first
|
||||
if ( pDataMap->baseMap )
|
||||
{
|
||||
SwapFieldsToTargetEndian( pOutputBuffer, pBaseData, pDataMap->baseMap );
|
||||
}
|
||||
|
||||
typedescription_t *pFields = pDataMap->dataDesc;
|
||||
int fieldCount = pDataMap->dataNumFields;
|
||||
for ( int i = 0; i < fieldCount; ++i )
|
||||
{
|
||||
typedescription_t *pField = &pFields[i];
|
||||
SwapFieldToTargetEndian( (BYTE*)pOutputBuffer + pField->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
(BYTE*)pBaseData + pField->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
pField );
|
||||
}
|
||||
}
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Low level byte swapping routines.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#include "byteswap.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copy a single field from the input buffer to the output buffer, swapping the bytes if necessary
|
||||
//-----------------------------------------------------------------------------
|
||||
void CByteswap::SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField )
|
||||
{
|
||||
switch ( pField->fieldType )
|
||||
{
|
||||
case FIELD_CHARACTER:
|
||||
SwapBufferToTargetEndian<char>( (char*)pOutputBuffer, (char*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_BOOLEAN:
|
||||
SwapBufferToTargetEndian<bool>( (bool*)pOutputBuffer, (bool*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_SHORT:
|
||||
SwapBufferToTargetEndian<short>( (short*)pOutputBuffer, (short*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_FLOAT:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_INTEGER:
|
||||
SwapBufferToTargetEndian<int>( (int*)pOutputBuffer, (int*)pData, pField->fieldSize );
|
||||
break;
|
||||
|
||||
case FIELD_VECTOR:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 3 );
|
||||
break;
|
||||
|
||||
case FIELD_VECTOR2D:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 2 );
|
||||
break;
|
||||
|
||||
case FIELD_QUATERNION:
|
||||
SwapBufferToTargetEndian<uint>( (uint*)pOutputBuffer, (uint*)pData, pField->fieldSize * 4 );
|
||||
break;
|
||||
|
||||
case FIELD_EMBEDDED:
|
||||
{
|
||||
typedescription_t *pEmbed = pField->td->dataDesc;
|
||||
for ( int i = 0; i < pField->fieldSize; ++i )
|
||||
{
|
||||
SwapFieldsToTargetEndian( (byte*)pOutputBuffer + pEmbed->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
(byte*)pData + pEmbed->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
pField->td );
|
||||
|
||||
pOutputBuffer = (byte*)pOutputBuffer + pField->fieldSizeInBytes;
|
||||
pData = (byte*)pData + pField->fieldSizeInBytes;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Write a block of fields. Works a bit like the saverestore code.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CByteswap::SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap )
|
||||
{
|
||||
// deal with base class first
|
||||
if ( pDataMap->baseMap )
|
||||
{
|
||||
SwapFieldsToTargetEndian( pOutputBuffer, pBaseData, pDataMap->baseMap );
|
||||
}
|
||||
|
||||
typedescription_t *pFields = pDataMap->dataDesc;
|
||||
int fieldCount = pDataMap->dataNumFields;
|
||||
for ( int i = 0; i < fieldCount; ++i )
|
||||
{
|
||||
typedescription_t *pField = &pFields[i];
|
||||
SwapFieldToTargetEndian( (BYTE*)pOutputBuffer + pField->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
(BYTE*)pBaseData + pField->fieldOffset[ TD_OFFSET_NORMAL ],
|
||||
pField );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#include <string.h>
|
||||
#include "characterset.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: builds a simple lookup table of a group of important characters
|
||||
// Input : *pParseGroup - pointer to the buffer for the group
|
||||
// *pGroupString - null terminated list of characters to flag
|
||||
//-----------------------------------------------------------------------------
|
||||
void CharacterSetBuild( characterset_t *pSetBuffer, const char *pszSetString )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// Test our pointers
|
||||
if ( !pSetBuffer || !pszSetString )
|
||||
return;
|
||||
|
||||
memset( pSetBuffer->set, 0, sizeof(pSetBuffer->set) );
|
||||
|
||||
while ( pszSetString[i] )
|
||||
{
|
||||
pSetBuffer->set[ pszSetString[i] ] = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#include <string.h>
|
||||
#include "characterset.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: builds a simple lookup table of a group of important characters
|
||||
// Input : *pParseGroup - pointer to the buffer for the group
|
||||
// *pGroupString - null terminated list of characters to flag
|
||||
//-----------------------------------------------------------------------------
|
||||
void CharacterSetBuild( characterset_t *pSetBuffer, const char *pszSetString )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
// Test our pointers
|
||||
if ( !pSetBuffer || !pszSetString )
|
||||
return;
|
||||
|
||||
memset( pSetBuffer->set, 0, sizeof(pSetBuffer->set) );
|
||||
|
||||
while ( pszSetString[i] )
|
||||
{
|
||||
pSetBuffer->set[ pszSetString[i] ] = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,180 +1,180 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Generic CRC functions
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "commonmacros.h"
|
||||
#include "checksum_crc.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define CRC32_INIT_VALUE 0xFFFFFFFFUL
|
||||
#define CRC32_XOR_VALUE 0xFFFFFFFFUL
|
||||
|
||||
#define NUM_BYTES 256
|
||||
static const CRC32_t pulCRCTable[NUM_BYTES] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
void CRC32_Init(CRC32_t *pulCRC)
|
||||
{
|
||||
*pulCRC = CRC32_INIT_VALUE;
|
||||
}
|
||||
|
||||
void CRC32_Final(CRC32_t *pulCRC)
|
||||
{
|
||||
*pulCRC ^= CRC32_XOR_VALUE;
|
||||
}
|
||||
|
||||
CRC32_t CRC32_GetTableEntry( unsigned int slot )
|
||||
{
|
||||
return pulCRCTable[(unsigned char)slot];
|
||||
}
|
||||
|
||||
void CRC32_ProcessBuffer(CRC32_t *pulCRC, const void *pBuffer, int nBuffer)
|
||||
{
|
||||
CRC32_t ulCrc = *pulCRC;
|
||||
unsigned char *pb = (unsigned char *)pBuffer;
|
||||
unsigned int nFront;
|
||||
int nMain;
|
||||
|
||||
JustAfew:
|
||||
|
||||
switch (nBuffer)
|
||||
{
|
||||
case 7:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 6:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 5:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 4:
|
||||
ulCrc ^= LittleLong( *(CRC32_t *)pb );
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
*pulCRC = ulCrc;
|
||||
return;
|
||||
|
||||
case 3:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 2:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 1:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 0:
|
||||
*pulCRC = ulCrc;
|
||||
return;
|
||||
}
|
||||
|
||||
// We may need to do some alignment work up front, and at the end, so that
|
||||
// the main loop is aligned and only has to worry about 8 byte at a time.
|
||||
//
|
||||
// The low-order two bits of pb and nBuffer in total control the
|
||||
// upfront work.
|
||||
//
|
||||
nFront = ((unsigned int)pb) & 3;
|
||||
nBuffer -= nFront;
|
||||
switch (nFront)
|
||||
{
|
||||
case 3:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
case 2:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
case 1:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
}
|
||||
|
||||
nMain = nBuffer >> 3;
|
||||
while (nMain--)
|
||||
{
|
||||
ulCrc ^= LittleLong( *(CRC32_t *)pb );
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc ^= LittleLong( *(CRC32_t *)(pb + 4) );
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
pb += 8;
|
||||
}
|
||||
|
||||
nBuffer &= 7;
|
||||
goto JustAfew;
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Generic CRC functions
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "commonmacros.h"
|
||||
#include "checksum_crc.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define CRC32_INIT_VALUE 0xFFFFFFFFUL
|
||||
#define CRC32_XOR_VALUE 0xFFFFFFFFUL
|
||||
|
||||
#define NUM_BYTES 256
|
||||
static const CRC32_t pulCRCTable[NUM_BYTES] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
|
||||
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
|
||||
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
|
||||
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
|
||||
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
|
||||
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
|
||||
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
|
||||
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
|
||||
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
|
||||
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
|
||||
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
|
||||
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
|
||||
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
|
||||
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
|
||||
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
|
||||
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
|
||||
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
|
||||
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
void CRC32_Init(CRC32_t *pulCRC)
|
||||
{
|
||||
*pulCRC = CRC32_INIT_VALUE;
|
||||
}
|
||||
|
||||
void CRC32_Final(CRC32_t *pulCRC)
|
||||
{
|
||||
*pulCRC ^= CRC32_XOR_VALUE;
|
||||
}
|
||||
|
||||
CRC32_t CRC32_GetTableEntry( unsigned int slot )
|
||||
{
|
||||
return pulCRCTable[(unsigned char)slot];
|
||||
}
|
||||
|
||||
void CRC32_ProcessBuffer(CRC32_t *pulCRC, const void *pBuffer, int nBuffer)
|
||||
{
|
||||
CRC32_t ulCrc = *pulCRC;
|
||||
unsigned char *pb = (unsigned char *)pBuffer;
|
||||
unsigned int nFront;
|
||||
int nMain;
|
||||
|
||||
JustAfew:
|
||||
|
||||
switch (nBuffer)
|
||||
{
|
||||
case 7:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 6:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 5:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 4:
|
||||
ulCrc ^= LittleLong( *(CRC32_t *)pb );
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
*pulCRC = ulCrc;
|
||||
return;
|
||||
|
||||
case 3:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 2:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 1:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
|
||||
case 0:
|
||||
*pulCRC = ulCrc;
|
||||
return;
|
||||
}
|
||||
|
||||
// We may need to do some alignment work up front, and at the end, so that
|
||||
// the main loop is aligned and only has to worry about 8 byte at a time.
|
||||
//
|
||||
// The low-order two bits of pb and nBuffer in total control the
|
||||
// upfront work.
|
||||
//
|
||||
nFront = ((unsigned int)pb) & 3;
|
||||
nBuffer -= nFront;
|
||||
switch (nFront)
|
||||
{
|
||||
case 3:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
case 2:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
case 1:
|
||||
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
}
|
||||
|
||||
nMain = nBuffer >> 3;
|
||||
while (nMain--)
|
||||
{
|
||||
ulCrc ^= LittleLong( *(CRC32_t *)pb );
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc ^= LittleLong( *(CRC32_t *)(pb + 4) );
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
|
||||
pb += 8;
|
||||
}
|
||||
|
||||
nBuffer &= 7;
|
||||
goto JustAfew;
|
||||
}
|
||||
|
||||
@@ -1,305 +1,305 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "commonmacros.h"
|
||||
#include "checksum_md5.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// The four core functions - F1 is optimized somewhat
|
||||
// #define F1(x, y, z) (x & y | ~x & z)
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
// This is the central step in the MD5 algorithm.
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
// reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
// the data and converts bytes into longwords for this routine.
|
||||
// Input : buf[4] -
|
||||
// in[16] -
|
||||
// Output : static void
|
||||
//-----------------------------------------------------------------------------
|
||||
static void MD5Transform(unsigned int buf[4], unsigned int const in[16])
|
||||
{
|
||||
register unsigned int a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Start MD5 accumulation. Set bit count to 0 and buffer to mysterious initialization constants.
|
||||
|
||||
// Input : *ctx -
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Init(MD5Context_t *ctx)
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update context to reflect the concatenation of another buffer full of bytes.
|
||||
// Input : *ctx -
|
||||
// *buf -
|
||||
// len -
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Update(MD5Context_t *ctx, unsigned char const *buf, unsigned int len)
|
||||
{
|
||||
unsigned int t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = t + ((unsigned int) len << 3)) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if (t)
|
||||
{
|
||||
unsigned char *p = (unsigned char *) ctx->in + t;
|
||||
|
||||
t = 64 - t;
|
||||
if (len < t)
|
||||
{
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
//byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64)
|
||||
{
|
||||
memcpy(ctx->in, buf, 64);
|
||||
//byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
// 1 0* (64-bit count of bits processed, MSB-first)
|
||||
// Input : digest[MD5_DIGEST_LENGTH] -
|
||||
// *ctx -
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5Context_t *ctx)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8)
|
||||
{
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
//byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count - 8);
|
||||
}
|
||||
//byteReverse(ctx->in, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
((unsigned int *) ctx->in)[14] = ctx->bits[0];
|
||||
((unsigned int *) ctx->in)[15] = ctx->bits[1];
|
||||
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
//byteReverse((unsigned char *) ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, MD5_DIGEST_LENGTH);
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *hash -
|
||||
// hashlen -
|
||||
// Output : char
|
||||
//-----------------------------------------------------------------------------
|
||||
char *MD5_Print( unsigned char *hash, int hashlen )
|
||||
{
|
||||
static char szReturn[64];
|
||||
|
||||
Assert( hashlen <= 32 );
|
||||
|
||||
Q_binarytohex( hash, hashlen, szReturn, sizeof( szReturn ) );
|
||||
return szReturn;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: generate pseudo random number from a seed number
|
||||
// Input : seed number
|
||||
// Output : pseudo random number
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int MD5_PseudoRandom(unsigned int nSeed)
|
||||
{
|
||||
MD5Context_t ctx;
|
||||
unsigned char digest[MD5_DIGEST_LENGTH]; // The MD5 Hash
|
||||
|
||||
memset( &ctx, 0, sizeof( ctx ) );
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char*)&nSeed, sizeof(nSeed) );
|
||||
MD5Final(digest, &ctx);
|
||||
|
||||
return *(unsigned int*)(digest+6); // use 4 middle bytes for random value
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MD5_Compare( const MD5Value_t &data, const MD5Value_t &compare )
|
||||
{
|
||||
return V_memcmp( data.bits, compare.bits, MD5_DIGEST_LENGTH ) == 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Value_t::Zero()
|
||||
{
|
||||
V_memset( bits, 0, sizeof( bits ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MD5Value_t::IsZero() const
|
||||
{
|
||||
for ( int i = 0 ; i < Q_ARRAYSIZE( bits ) ; ++i )
|
||||
{
|
||||
if ( bits[i] != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5_ProcessSingleBuffer( const void *p, int len, MD5Value_t &md5Result )
|
||||
{
|
||||
Assert( len >= 0 );
|
||||
MD5Context_t ctx;
|
||||
MD5Init( &ctx );
|
||||
MD5Update( &ctx, (unsigned char const *)p, len );
|
||||
MD5Final( md5Result.bits, &ctx );
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "commonmacros.h"
|
||||
#include "checksum_md5.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// The four core functions - F1 is optimized somewhat
|
||||
// #define F1(x, y, z) (x & y | ~x & z)
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
// This is the central step in the MD5 algorithm.
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
// reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
// the data and converts bytes into longwords for this routine.
|
||||
// Input : buf[4] -
|
||||
// in[16] -
|
||||
// Output : static void
|
||||
//-----------------------------------------------------------------------------
|
||||
static void MD5Transform(unsigned int buf[4], unsigned int const in[16])
|
||||
{
|
||||
register unsigned int a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Start MD5 accumulation. Set bit count to 0 and buffer to mysterious initialization constants.
|
||||
|
||||
// Input : *ctx -
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Init(MD5Context_t *ctx)
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update context to reflect the concatenation of another buffer full of bytes.
|
||||
// Input : *ctx -
|
||||
// *buf -
|
||||
// len -
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Update(MD5Context_t *ctx, unsigned char const *buf, unsigned int len)
|
||||
{
|
||||
unsigned int t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = t + ((unsigned int) len << 3)) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if (t)
|
||||
{
|
||||
unsigned char *p = (unsigned char *) ctx->in + t;
|
||||
|
||||
t = 64 - t;
|
||||
if (len < t)
|
||||
{
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
//byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64)
|
||||
{
|
||||
memcpy(ctx->in, buf, 64);
|
||||
//byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
memcpy(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
// 1 0* (64-bit count of bits processed, MSB-first)
|
||||
// Input : digest[MD5_DIGEST_LENGTH] -
|
||||
// *ctx -
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5Context_t *ctx)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8)
|
||||
{
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
//byteReverse(ctx->in, 16);
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in, 0, 56);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count - 8);
|
||||
}
|
||||
//byteReverse(ctx->in, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
((unsigned int *) ctx->in)[14] = ctx->bits[0];
|
||||
((unsigned int *) ctx->in)[15] = ctx->bits[1];
|
||||
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
//byteReverse((unsigned char *) ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, MD5_DIGEST_LENGTH);
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *hash -
|
||||
// hashlen -
|
||||
// Output : char
|
||||
//-----------------------------------------------------------------------------
|
||||
char *MD5_Print( unsigned char *hash, int hashlen )
|
||||
{
|
||||
static char szReturn[64];
|
||||
|
||||
Assert( hashlen <= 32 );
|
||||
|
||||
Q_binarytohex( hash, hashlen, szReturn, sizeof( szReturn ) );
|
||||
return szReturn;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: generate pseudo random number from a seed number
|
||||
// Input : seed number
|
||||
// Output : pseudo random number
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int MD5_PseudoRandom(unsigned int nSeed)
|
||||
{
|
||||
MD5Context_t ctx;
|
||||
unsigned char digest[MD5_DIGEST_LENGTH]; // The MD5 Hash
|
||||
|
||||
memset( &ctx, 0, sizeof( ctx ) );
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (unsigned char*)&nSeed, sizeof(nSeed) );
|
||||
MD5Final(digest, &ctx);
|
||||
|
||||
return *(unsigned int*)(digest+6); // use 4 middle bytes for random value
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MD5_Compare( const MD5Value_t &data, const MD5Value_t &compare )
|
||||
{
|
||||
return V_memcmp( data.bits, compare.bits, MD5_DIGEST_LENGTH ) == 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5Value_t::Zero()
|
||||
{
|
||||
V_memset( bits, 0, sizeof( bits ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool MD5Value_t::IsZero() const
|
||||
{
|
||||
for ( int i = 0 ; i < Q_ARRAYSIZE( bits ) ; ++i )
|
||||
{
|
||||
if ( bits[i] != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void MD5_ProcessSingleBuffer( const void *p, int len, MD5Value_t &md5Result )
|
||||
{
|
||||
Assert( len >= 0 );
|
||||
MD5Context_t ctx;
|
||||
MD5Init( &ctx );
|
||||
MD5Update( &ctx, (unsigned char const *)p, len );
|
||||
MD5Final( md5Result.bits, &ctx );
|
||||
}
|
||||
|
||||
@@ -1,299 +1,299 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implementation of SHA-1
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
100% free public domain implementation of the SHA-1
|
||||
algorithm by Dominik Reichl <dominik.reichl@t-online.de>
|
||||
|
||||
|
||||
=== Test Vectors (from FIPS PUB 180-1) ===
|
||||
|
||||
SHA1("abc") =
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
|
||||
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
|
||||
SHA1(A million repetitions of "a") =
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
#include "checksum_sha1.h"
|
||||
#else
|
||||
//
|
||||
// This path is build in the CEG/DRM projects where we require that no CRT references are made !
|
||||
//
|
||||
#include <intrin.h> // memcpy, memset etc... will be inlined.
|
||||
#include "tier1/checksum_sha1.h"
|
||||
#endif
|
||||
|
||||
#define MAX_FILE_READ_BUFFER 8000
|
||||
|
||||
// Rotate x bits to the left
|
||||
#ifndef ROL32
|
||||
#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
|
||||
#endif
|
||||
|
||||
#ifdef SHA1_LITTLE_ENDIAN
|
||||
#define SHABLK0(i) (m_block->l[i] = \
|
||||
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
|
||||
#else
|
||||
#define SHABLK0(i) (m_block->l[i])
|
||||
#endif
|
||||
|
||||
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
|
||||
^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
|
||||
|
||||
// SHA-1 rounds
|
||||
#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
|
||||
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
Minimum_CSHA1::Minimum_CSHA1()
|
||||
#else
|
||||
CSHA1::CSHA1()
|
||||
#endif
|
||||
{
|
||||
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
|
||||
|
||||
Reset();
|
||||
}
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
Minimum_CSHA1::~Minimum_CSHA1()
|
||||
#else
|
||||
CSHA1::~CSHA1()
|
||||
#endif
|
||||
{
|
||||
// Reset();
|
||||
}
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Reset()
|
||||
#else
|
||||
void CSHA1::Reset()
|
||||
#endif
|
||||
{
|
||||
// SHA1 initialization constants
|
||||
m_state[0] = 0x67452301;
|
||||
m_state[1] = 0xEFCDAB89;
|
||||
m_state[2] = 0x98BADCFE;
|
||||
m_state[3] = 0x10325476;
|
||||
m_state[4] = 0xC3D2E1F0;
|
||||
|
||||
m_count[0] = 0;
|
||||
m_count[1] = 0;
|
||||
}
|
||||
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Transform(unsigned long state[5], unsigned char buffer[64])
|
||||
#else
|
||||
void CSHA1::Transform(unsigned long state[5], unsigned char buffer[64])
|
||||
#endif
|
||||
{
|
||||
unsigned long a = 0, b = 0, c = 0, d = 0, e = 0;
|
||||
|
||||
memcpy(m_block, buffer, 64);
|
||||
|
||||
// Copy state[] to working vars
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
|
||||
// 4 rounds of 20 operations each. Loop unrolled.
|
||||
_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
|
||||
_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
|
||||
_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
|
||||
_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
|
||||
_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
|
||||
_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
|
||||
_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
|
||||
_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
|
||||
_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
|
||||
_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
|
||||
_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
|
||||
_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
|
||||
_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
|
||||
_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
|
||||
_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
|
||||
_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
|
||||
_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
|
||||
_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
|
||||
_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
|
||||
_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
|
||||
|
||||
// Add the working vars back into state[]
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
// Wipe variables
|
||||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
// Use this function to hash in binary data and strings
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Update(unsigned char *data, unsigned int len)
|
||||
#else
|
||||
void CSHA1::Update(unsigned char *data, unsigned int len)
|
||||
#endif
|
||||
{
|
||||
unsigned long i = 0, j;
|
||||
|
||||
j = (m_count[0] >> 3) & 63;
|
||||
|
||||
if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
|
||||
|
||||
m_count[1] += (len >> 29);
|
||||
|
||||
if((j + len) > 63)
|
||||
{
|
||||
memcpy(&m_buffer[j], data, (i = 64 - j));
|
||||
Transform(m_state, m_buffer);
|
||||
|
||||
for (; i+63 < len; i += 64)
|
||||
Transform(m_state, &data[i]);
|
||||
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
|
||||
memcpy(&m_buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
// Hash in file contents
|
||||
bool CSHA1::HashFile(char *szFileName)
|
||||
{
|
||||
unsigned long ulFileSize = 0, ulRest = 0, ulBlocks = 0;
|
||||
unsigned long i = 0;
|
||||
unsigned char uData[MAX_FILE_READ_BUFFER];
|
||||
FILE *fIn = NULL;
|
||||
|
||||
if(szFileName == NULL) return(false);
|
||||
|
||||
if((fIn = fopen(szFileName, "rb")) == NULL) return(false);
|
||||
|
||||
fseek(fIn, 0, SEEK_END);
|
||||
ulFileSize = ftell(fIn);
|
||||
fseek(fIn, 0, SEEK_SET);
|
||||
|
||||
ulRest = ulFileSize % MAX_FILE_READ_BUFFER;
|
||||
ulBlocks = ulFileSize / MAX_FILE_READ_BUFFER;
|
||||
|
||||
for(i = 0; i < ulBlocks; i++)
|
||||
{
|
||||
fread(uData, 1, MAX_FILE_READ_BUFFER, fIn);
|
||||
Update(uData, MAX_FILE_READ_BUFFER);
|
||||
}
|
||||
|
||||
if(ulRest != 0)
|
||||
{
|
||||
fread(uData, 1, ulRest, fIn);
|
||||
Update(uData, ulRest);
|
||||
}
|
||||
|
||||
fclose(fIn);
|
||||
fIn = NULL;
|
||||
|
||||
return(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Final()
|
||||
#else
|
||||
void CSHA1::Final()
|
||||
#endif
|
||||
{
|
||||
unsigned long i = 0;
|
||||
unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
|
||||
|
||||
Update((unsigned char *)"\200", 1);
|
||||
|
||||
while ((m_count[0] & 504) != 448)
|
||||
Update((unsigned char *)"\0", 1);
|
||||
|
||||
Update(finalcount, 8); // Cause a SHA1Transform()
|
||||
|
||||
for (i = 0; i < k_cubHash; i++)
|
||||
{
|
||||
m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
|
||||
}
|
||||
|
||||
// Wipe variables for security reasons
|
||||
i = 0;
|
||||
memset(m_buffer, 0, sizeof(m_buffer) );
|
||||
memset(m_state, 0, sizeof(m_state) );
|
||||
memset(m_count, 0, sizeof(m_count) );
|
||||
memset(finalcount, 0, sizeof( finalcount) );
|
||||
|
||||
Transform(m_state, m_buffer);
|
||||
}
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
// Get the final hash as a pre-formatted string
|
||||
void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
|
||||
{
|
||||
unsigned char i = 0;
|
||||
char szTemp[12];
|
||||
|
||||
if(szReport == NULL) return;
|
||||
|
||||
if(uReportType == REPORT_HEX)
|
||||
{
|
||||
sprintf(szTemp, "%02X", m_digest[0]);
|
||||
strcat(szReport, szTemp);
|
||||
|
||||
for(i = 1; i < k_cubHash; i++)
|
||||
{
|
||||
sprintf(szTemp, " %02X", m_digest[i]);
|
||||
strcat(szReport, szTemp);
|
||||
}
|
||||
}
|
||||
else if(uReportType == REPORT_DIGIT)
|
||||
{
|
||||
sprintf(szTemp, "%u", m_digest[0]);
|
||||
strcat(szReport, szTemp);
|
||||
|
||||
for(i = 1; i < k_cubHash; i++)
|
||||
{
|
||||
sprintf(szTemp, " %u", m_digest[i]);
|
||||
strcat(szReport, szTemp);
|
||||
}
|
||||
}
|
||||
else strcpy(szReport, "Error: Unknown report type!");
|
||||
}
|
||||
#endif // _MINIMUM_BUILD_
|
||||
|
||||
// Get the raw message digest
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::GetHash(unsigned char *uDest)
|
||||
#else
|
||||
void CSHA1::GetHash(unsigned char *uDest)
|
||||
#endif
|
||||
{
|
||||
memcpy(uDest, m_digest, k_cubHash);
|
||||
}
|
||||
|
||||
#ifndef _MINIMUM_BUILD_
|
||||
// utility hash comparison function
|
||||
bool HashLessFunc( SHADigest_t const &lhs, SHADigest_t const &rhs )
|
||||
{
|
||||
int iRes = memcmp( &lhs, &rhs, sizeof( SHADigest_t ) );
|
||||
return ( iRes < 0 );
|
||||
}
|
||||
#endif
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implementation of SHA-1
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
100% free public domain implementation of the SHA-1
|
||||
algorithm by Dominik Reichl <dominik.reichl@t-online.de>
|
||||
|
||||
|
||||
=== Test Vectors (from FIPS PUB 180-1) ===
|
||||
|
||||
SHA1("abc") =
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
|
||||
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
|
||||
SHA1(A million repetitions of "a") =
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
#include "checksum_sha1.h"
|
||||
#else
|
||||
//
|
||||
// This path is build in the CEG/DRM projects where we require that no CRT references are made !
|
||||
//
|
||||
#include <intrin.h> // memcpy, memset etc... will be inlined.
|
||||
#include "tier1/checksum_sha1.h"
|
||||
#endif
|
||||
|
||||
#define MAX_FILE_READ_BUFFER 8000
|
||||
|
||||
// Rotate x bits to the left
|
||||
#ifndef ROL32
|
||||
#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
|
||||
#endif
|
||||
|
||||
#ifdef SHA1_LITTLE_ENDIAN
|
||||
#define SHABLK0(i) (m_block->l[i] = \
|
||||
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
|
||||
#else
|
||||
#define SHABLK0(i) (m_block->l[i])
|
||||
#endif
|
||||
|
||||
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
|
||||
^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
|
||||
|
||||
// SHA-1 rounds
|
||||
#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
|
||||
#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
|
||||
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
Minimum_CSHA1::Minimum_CSHA1()
|
||||
#else
|
||||
CSHA1::CSHA1()
|
||||
#endif
|
||||
{
|
||||
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
|
||||
|
||||
Reset();
|
||||
}
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
Minimum_CSHA1::~Minimum_CSHA1()
|
||||
#else
|
||||
CSHA1::~CSHA1()
|
||||
#endif
|
||||
{
|
||||
// Reset();
|
||||
}
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Reset()
|
||||
#else
|
||||
void CSHA1::Reset()
|
||||
#endif
|
||||
{
|
||||
// SHA1 initialization constants
|
||||
m_state[0] = 0x67452301;
|
||||
m_state[1] = 0xEFCDAB89;
|
||||
m_state[2] = 0x98BADCFE;
|
||||
m_state[3] = 0x10325476;
|
||||
m_state[4] = 0xC3D2E1F0;
|
||||
|
||||
m_count[0] = 0;
|
||||
m_count[1] = 0;
|
||||
}
|
||||
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Transform(unsigned long state[5], unsigned char buffer[64])
|
||||
#else
|
||||
void CSHA1::Transform(unsigned long state[5], unsigned char buffer[64])
|
||||
#endif
|
||||
{
|
||||
unsigned long a = 0, b = 0, c = 0, d = 0, e = 0;
|
||||
|
||||
memcpy(m_block, buffer, 64);
|
||||
|
||||
// Copy state[] to working vars
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
|
||||
// 4 rounds of 20 operations each. Loop unrolled.
|
||||
_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
|
||||
_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
|
||||
_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
|
||||
_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
|
||||
_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
|
||||
_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
|
||||
_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
|
||||
_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
|
||||
_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
|
||||
_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
|
||||
_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
|
||||
_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
|
||||
_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
|
||||
_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
|
||||
_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
|
||||
_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
|
||||
_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
|
||||
_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
|
||||
_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
|
||||
_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
|
||||
|
||||
// Add the working vars back into state[]
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
// Wipe variables
|
||||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
// Use this function to hash in binary data and strings
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Update(unsigned char *data, unsigned int len)
|
||||
#else
|
||||
void CSHA1::Update(unsigned char *data, unsigned int len)
|
||||
#endif
|
||||
{
|
||||
unsigned long i = 0, j;
|
||||
|
||||
j = (m_count[0] >> 3) & 63;
|
||||
|
||||
if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
|
||||
|
||||
m_count[1] += (len >> 29);
|
||||
|
||||
if((j + len) > 63)
|
||||
{
|
||||
memcpy(&m_buffer[j], data, (i = 64 - j));
|
||||
Transform(m_state, m_buffer);
|
||||
|
||||
for (; i+63 < len; i += 64)
|
||||
Transform(m_state, &data[i]);
|
||||
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
|
||||
memcpy(&m_buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
// Hash in file contents
|
||||
bool CSHA1::HashFile(char *szFileName)
|
||||
{
|
||||
unsigned long ulFileSize = 0, ulRest = 0, ulBlocks = 0;
|
||||
unsigned long i = 0;
|
||||
unsigned char uData[MAX_FILE_READ_BUFFER];
|
||||
FILE *fIn = NULL;
|
||||
|
||||
if(szFileName == NULL) return(false);
|
||||
|
||||
if((fIn = fopen(szFileName, "rb")) == NULL) return(false);
|
||||
|
||||
fseek(fIn, 0, SEEK_END);
|
||||
ulFileSize = ftell(fIn);
|
||||
fseek(fIn, 0, SEEK_SET);
|
||||
|
||||
ulRest = ulFileSize % MAX_FILE_READ_BUFFER;
|
||||
ulBlocks = ulFileSize / MAX_FILE_READ_BUFFER;
|
||||
|
||||
for(i = 0; i < ulBlocks; i++)
|
||||
{
|
||||
fread(uData, 1, MAX_FILE_READ_BUFFER, fIn);
|
||||
Update(uData, MAX_FILE_READ_BUFFER);
|
||||
}
|
||||
|
||||
if(ulRest != 0)
|
||||
{
|
||||
fread(uData, 1, ulRest, fIn);
|
||||
Update(uData, ulRest);
|
||||
}
|
||||
|
||||
fclose(fIn);
|
||||
fIn = NULL;
|
||||
|
||||
return(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::Final()
|
||||
#else
|
||||
void CSHA1::Final()
|
||||
#endif
|
||||
{
|
||||
unsigned long i = 0;
|
||||
unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
|
||||
|
||||
Update((unsigned char *)"\200", 1);
|
||||
|
||||
while ((m_count[0] & 504) != 448)
|
||||
Update((unsigned char *)"\0", 1);
|
||||
|
||||
Update(finalcount, 8); // Cause a SHA1Transform()
|
||||
|
||||
for (i = 0; i < k_cubHash; i++)
|
||||
{
|
||||
m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
|
||||
}
|
||||
|
||||
// Wipe variables for security reasons
|
||||
i = 0;
|
||||
memset(m_buffer, 0, sizeof(m_buffer) );
|
||||
memset(m_state, 0, sizeof(m_state) );
|
||||
memset(m_count, 0, sizeof(m_count) );
|
||||
memset(finalcount, 0, sizeof( finalcount) );
|
||||
|
||||
Transform(m_state, m_buffer);
|
||||
}
|
||||
|
||||
#if !defined(_MINIMUM_BUILD_)
|
||||
// Get the final hash as a pre-formatted string
|
||||
void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
|
||||
{
|
||||
unsigned char i = 0;
|
||||
char szTemp[12];
|
||||
|
||||
if(szReport == NULL) return;
|
||||
|
||||
if(uReportType == REPORT_HEX)
|
||||
{
|
||||
sprintf(szTemp, "%02X", m_digest[0]);
|
||||
strcat(szReport, szTemp);
|
||||
|
||||
for(i = 1; i < k_cubHash; i++)
|
||||
{
|
||||
sprintf(szTemp, " %02X", m_digest[i]);
|
||||
strcat(szReport, szTemp);
|
||||
}
|
||||
}
|
||||
else if(uReportType == REPORT_DIGIT)
|
||||
{
|
||||
sprintf(szTemp, "%u", m_digest[0]);
|
||||
strcat(szReport, szTemp);
|
||||
|
||||
for(i = 1; i < k_cubHash; i++)
|
||||
{
|
||||
sprintf(szTemp, " %u", m_digest[i]);
|
||||
strcat(szReport, szTemp);
|
||||
}
|
||||
}
|
||||
else strcpy(szReport, "Error: Unknown report type!");
|
||||
}
|
||||
#endif // _MINIMUM_BUILD_
|
||||
|
||||
// Get the raw message digest
|
||||
#ifdef _MINIMUM_BUILD_
|
||||
void Minimum_CSHA1::GetHash(unsigned char *uDest)
|
||||
#else
|
||||
void CSHA1::GetHash(unsigned char *uDest)
|
||||
#endif
|
||||
{
|
||||
memcpy(uDest, m_digest, k_cubHash);
|
||||
}
|
||||
|
||||
#ifndef _MINIMUM_BUILD_
|
||||
// utility hash comparison function
|
||||
bool HashLessFunc( SHADigest_t const &lhs, SHADigest_t const &rhs )
|
||||
{
|
||||
int iRes = memcmp( &lhs, &rhs, sizeof( SHADigest_t ) );
|
||||
return ( iRes < 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,411 +1,411 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "datamanager.h"
|
||||
|
||||
DECLARE_POINTER_HANDLE( memhandle_t );
|
||||
|
||||
#define AUTO_LOCK_DM() AUTO_LOCK_( CDataManagerBase, *this )
|
||||
|
||||
CDataManagerBase::CDataManagerBase( unsigned int maxSize )
|
||||
{
|
||||
m_targetMemorySize = maxSize;
|
||||
m_memUsed = 0;
|
||||
m_lruList = m_memoryLists.CreateList();
|
||||
m_lockList = m_memoryLists.CreateList();
|
||||
m_freeList = m_memoryLists.CreateList();
|
||||
m_listsAreFreed = 0;
|
||||
}
|
||||
|
||||
CDataManagerBase::~CDataManagerBase()
|
||||
{
|
||||
Assert( m_listsAreFreed );
|
||||
}
|
||||
|
||||
void CDataManagerBase::NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize )
|
||||
{
|
||||
Lock();
|
||||
m_memUsed += (int)newSize - (int)oldSize;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void CDataManagerBase::SetTargetSize( unsigned int targetSize )
|
||||
{
|
||||
m_targetMemorySize = targetSize;
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::FlushAllUnlocked()
|
||||
{
|
||||
Lock();
|
||||
|
||||
int nFlush = m_memoryLists.Count( m_lruList );
|
||||
void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
|
||||
CUtlVector<void *> destroyList( pScratch, nFlush );
|
||||
|
||||
unsigned nBytesInitial = MemUsed_Inline();
|
||||
|
||||
int node = m_memoryLists.Head(m_lruList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
int next = m_memoryLists.Next(node);
|
||||
m_memoryLists.Unlink( m_lruList, node );
|
||||
destroyList.AddToTail( GetForFreeByIndex( node ) );
|
||||
node = next;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
for ( int i = 0; i < nFlush; i++ )
|
||||
{
|
||||
DestroyResourceStorage( destroyList[i] );
|
||||
}
|
||||
|
||||
return ( nBytesInitial - MemUsed_Inline() );
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::FlushToTargetSize()
|
||||
{
|
||||
return EnsureCapacity(0);
|
||||
}
|
||||
|
||||
// Frees everything! The LRU AND the LOCKED items. This is only used to forcibly free the resources,
|
||||
// not to make space.
|
||||
|
||||
unsigned int CDataManagerBase::FlushAll()
|
||||
{
|
||||
Lock();
|
||||
|
||||
int nFlush = m_memoryLists.Count( m_lruList ) + m_memoryLists.Count( m_lockList );
|
||||
void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
|
||||
CUtlVector<void *> destroyList( pScratch, nFlush );
|
||||
|
||||
unsigned result = MemUsed_Inline();
|
||||
int node;
|
||||
int nextNode;
|
||||
|
||||
node = m_memoryLists.Head(m_lruList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
nextNode = m_memoryLists.Next(node);
|
||||
m_memoryLists.Unlink( m_lruList, node );
|
||||
destroyList.AddToTail( GetForFreeByIndex( node ) );
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
node = m_memoryLists.Head(m_lockList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
nextNode = m_memoryLists.Next(node);
|
||||
m_memoryLists.Unlink( m_lockList, node );
|
||||
m_memoryLists[node].lockCount = 0;
|
||||
destroyList.AddToTail( GetForFreeByIndex( node ) );
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
m_listsAreFreed = false;
|
||||
Unlock();
|
||||
|
||||
for ( int i = 0; i < nFlush; i++ )
|
||||
{
|
||||
DestroyResourceStorage( destroyList[i] );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge )
|
||||
{
|
||||
unsigned int nTargetSize = MemUsed_Inline() - nBytesToPurge;
|
||||
// Check for underflow
|
||||
if ( MemUsed_Inline() < nBytesToPurge )
|
||||
nTargetSize = 0;
|
||||
unsigned int nImpliedCapacity = MemTotal_Inline() - nTargetSize;
|
||||
return EnsureCapacity( nImpliedCapacity );
|
||||
}
|
||||
|
||||
|
||||
void CDataManagerBase::DestroyResource( memhandle_t handle )
|
||||
{
|
||||
Lock();
|
||||
unsigned short index = FromHandle( handle );
|
||||
if ( !m_memoryLists.IsValidIndex(index) )
|
||||
{
|
||||
Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
Assert( m_memoryLists[index].lockCount == 0 );
|
||||
if ( m_memoryLists[index].lockCount )
|
||||
BreakLock( handle );
|
||||
m_memoryLists.Unlink( m_lruList, index );
|
||||
void *p = GetForFreeByIndex( index );
|
||||
Unlock();
|
||||
|
||||
DestroyResourceStorage( p );
|
||||
}
|
||||
|
||||
|
||||
void *CDataManagerBase::LockResource( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lruList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lockList, memoryIndex );
|
||||
}
|
||||
Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1);
|
||||
m_memoryLists[memoryIndex].lockCount++;
|
||||
return m_memoryLists[memoryIndex].pStore;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CDataManagerBase::UnlockResource( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
Assert( m_memoryLists[memoryIndex].lockCount > 0 );
|
||||
if ( m_memoryLists[memoryIndex].lockCount > 0 )
|
||||
{
|
||||
m_memoryLists[memoryIndex].lockCount--;
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lockList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
|
||||
}
|
||||
}
|
||||
return m_memoryLists[memoryIndex].lockCount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
return m_memoryLists[memoryIndex].pStore;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void *CDataManagerBase::GetResource_NoLock( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
TouchByIndex( memoryIndex );
|
||||
return m_memoryLists[memoryIndex].pStore;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CDataManagerBase::TouchResource( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
TouchByIndex( FromHandle(handle) );
|
||||
}
|
||||
|
||||
void CDataManagerBase::MarkAsStale( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lruList, memoryIndex );
|
||||
m_memoryLists.LinkToHead( m_lruList, memoryIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CDataManagerBase::BreakLock( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount )
|
||||
{
|
||||
int nBroken = m_memoryLists[memoryIndex].lockCount;
|
||||
m_memoryLists[memoryIndex].lockCount = 0;
|
||||
m_memoryLists.Unlink( m_lockList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
|
||||
|
||||
return nBroken;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CDataManagerBase::BreakAllLocks()
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
int nBroken = 0;
|
||||
int node;
|
||||
int nextNode;
|
||||
|
||||
node = m_memoryLists.Head(m_lockList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
nBroken++;
|
||||
nextNode = m_memoryLists.Next(node);
|
||||
m_memoryLists[node].lockCount = 0;
|
||||
m_memoryLists.Unlink( m_lockList, node );
|
||||
m_memoryLists.LinkToTail( m_lruList, node );
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
return nBroken;
|
||||
|
||||
}
|
||||
|
||||
unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
int memoryIndex = m_memoryLists.Head(m_freeList);
|
||||
unsigned short list = ( bCreateLocked ) ? m_lockList : m_lruList;
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
m_memoryLists.Unlink( m_freeList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( list, memoryIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
memoryIndex = m_memoryLists.AddToTail( list );
|
||||
}
|
||||
|
||||
if ( bCreateLocked )
|
||||
{
|
||||
m_memoryLists[memoryIndex].lockCount++;
|
||||
}
|
||||
|
||||
return memoryIndex;
|
||||
}
|
||||
|
||||
memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
|
||||
mem.pStore = pStore;
|
||||
m_memUsed += realSize;
|
||||
return ToHandle(memoryIndex);
|
||||
}
|
||||
|
||||
void CDataManagerBase::TouchByIndex( unsigned short memoryIndex )
|
||||
{
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lruList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memhandle_t CDataManagerBase::ToHandle( unsigned short index )
|
||||
{
|
||||
unsigned int hiword = m_memoryLists.Element(index).serial;
|
||||
hiword <<= 16;
|
||||
index++;
|
||||
return (memhandle_t)( hiword|index );
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::TargetSize()
|
||||
{
|
||||
return MemTotal_Inline();
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::AvailableSize()
|
||||
{
|
||||
return MemAvailable_Inline();
|
||||
}
|
||||
|
||||
|
||||
unsigned int CDataManagerBase::UsedSize()
|
||||
{
|
||||
return MemUsed_Inline();
|
||||
}
|
||||
|
||||
// free resources until there is enough space to hold "size"
|
||||
unsigned int CDataManagerBase::EnsureCapacity( unsigned int size )
|
||||
{
|
||||
unsigned nBytesInitial = MemUsed_Inline();
|
||||
while ( MemUsed_Inline() > MemTotal_Inline() || MemAvailable_Inline() < size )
|
||||
{
|
||||
Lock();
|
||||
int lruIndex = m_memoryLists.Head( m_lruList );
|
||||
if ( lruIndex == m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
Unlock();
|
||||
break;
|
||||
}
|
||||
m_memoryLists.Unlink( m_lruList, lruIndex );
|
||||
void *p = GetForFreeByIndex( lruIndex );
|
||||
Unlock();
|
||||
DestroyResourceStorage( p );
|
||||
}
|
||||
return ( nBytesInitial - MemUsed_Inline() );
|
||||
}
|
||||
|
||||
// free this resource and move the handle to the free list
|
||||
void *CDataManagerBase::GetForFreeByIndex( unsigned short memoryIndex )
|
||||
{
|
||||
void *p = NULL;
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
Assert( m_memoryLists[memoryIndex].lockCount == 0 );
|
||||
|
||||
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
|
||||
unsigned size = GetRealSize( mem.pStore );
|
||||
if ( size > m_memUsed )
|
||||
{
|
||||
ExecuteOnce( Warning( "Data manager 'used' memory incorrect\n" ) );
|
||||
size = m_memUsed;
|
||||
}
|
||||
m_memUsed -= size;
|
||||
p = mem.pStore;
|
||||
mem.pStore = NULL;
|
||||
mem.serial++;
|
||||
m_memoryLists.LinkToTail( m_freeList, memoryIndex );
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// get a list of everything in the LRU
|
||||
void CDataManagerBase::GetLRUHandleList( CUtlVector< memhandle_t >& list )
|
||||
{
|
||||
for ( int node = m_memoryLists.Tail(m_lruList);
|
||||
node != m_memoryLists.InvalidIndex();
|
||||
node = m_memoryLists.Previous(node) )
|
||||
{
|
||||
list.AddToTail( ToHandle( node ) );
|
||||
}
|
||||
}
|
||||
|
||||
// get a list of everything locked
|
||||
void CDataManagerBase::GetLockHandleList( CUtlVector< memhandle_t >& list )
|
||||
{
|
||||
for ( int node = m_memoryLists.Head(m_lockList);
|
||||
node != m_memoryLists.InvalidIndex();
|
||||
node = m_memoryLists.Next(node) )
|
||||
{
|
||||
list.AddToTail( ToHandle( node ) );
|
||||
}
|
||||
}
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "datamanager.h"
|
||||
|
||||
DECLARE_POINTER_HANDLE( memhandle_t );
|
||||
|
||||
#define AUTO_LOCK_DM() AUTO_LOCK_( CDataManagerBase, *this )
|
||||
|
||||
CDataManagerBase::CDataManagerBase( unsigned int maxSize )
|
||||
{
|
||||
m_targetMemorySize = maxSize;
|
||||
m_memUsed = 0;
|
||||
m_lruList = m_memoryLists.CreateList();
|
||||
m_lockList = m_memoryLists.CreateList();
|
||||
m_freeList = m_memoryLists.CreateList();
|
||||
m_listsAreFreed = 0;
|
||||
}
|
||||
|
||||
CDataManagerBase::~CDataManagerBase()
|
||||
{
|
||||
Assert( m_listsAreFreed );
|
||||
}
|
||||
|
||||
void CDataManagerBase::NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize )
|
||||
{
|
||||
Lock();
|
||||
m_memUsed += (int)newSize - (int)oldSize;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
void CDataManagerBase::SetTargetSize( unsigned int targetSize )
|
||||
{
|
||||
m_targetMemorySize = targetSize;
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::FlushAllUnlocked()
|
||||
{
|
||||
Lock();
|
||||
|
||||
int nFlush = m_memoryLists.Count( m_lruList );
|
||||
void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
|
||||
CUtlVector<void *> destroyList( pScratch, nFlush );
|
||||
|
||||
unsigned nBytesInitial = MemUsed_Inline();
|
||||
|
||||
int node = m_memoryLists.Head(m_lruList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
int next = m_memoryLists.Next(node);
|
||||
m_memoryLists.Unlink( m_lruList, node );
|
||||
destroyList.AddToTail( GetForFreeByIndex( node ) );
|
||||
node = next;
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
for ( int i = 0; i < nFlush; i++ )
|
||||
{
|
||||
DestroyResourceStorage( destroyList[i] );
|
||||
}
|
||||
|
||||
return ( nBytesInitial - MemUsed_Inline() );
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::FlushToTargetSize()
|
||||
{
|
||||
return EnsureCapacity(0);
|
||||
}
|
||||
|
||||
// Frees everything! The LRU AND the LOCKED items. This is only used to forcibly free the resources,
|
||||
// not to make space.
|
||||
|
||||
unsigned int CDataManagerBase::FlushAll()
|
||||
{
|
||||
Lock();
|
||||
|
||||
int nFlush = m_memoryLists.Count( m_lruList ) + m_memoryLists.Count( m_lockList );
|
||||
void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
|
||||
CUtlVector<void *> destroyList( pScratch, nFlush );
|
||||
|
||||
unsigned result = MemUsed_Inline();
|
||||
int node;
|
||||
int nextNode;
|
||||
|
||||
node = m_memoryLists.Head(m_lruList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
nextNode = m_memoryLists.Next(node);
|
||||
m_memoryLists.Unlink( m_lruList, node );
|
||||
destroyList.AddToTail( GetForFreeByIndex( node ) );
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
node = m_memoryLists.Head(m_lockList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
nextNode = m_memoryLists.Next(node);
|
||||
m_memoryLists.Unlink( m_lockList, node );
|
||||
m_memoryLists[node].lockCount = 0;
|
||||
destroyList.AddToTail( GetForFreeByIndex( node ) );
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
m_listsAreFreed = false;
|
||||
Unlock();
|
||||
|
||||
for ( int i = 0; i < nFlush; i++ )
|
||||
{
|
||||
DestroyResourceStorage( destroyList[i] );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge )
|
||||
{
|
||||
unsigned int nTargetSize = MemUsed_Inline() - nBytesToPurge;
|
||||
// Check for underflow
|
||||
if ( MemUsed_Inline() < nBytesToPurge )
|
||||
nTargetSize = 0;
|
||||
unsigned int nImpliedCapacity = MemTotal_Inline() - nTargetSize;
|
||||
return EnsureCapacity( nImpliedCapacity );
|
||||
}
|
||||
|
||||
|
||||
void CDataManagerBase::DestroyResource( memhandle_t handle )
|
||||
{
|
||||
Lock();
|
||||
unsigned short index = FromHandle( handle );
|
||||
if ( !m_memoryLists.IsValidIndex(index) )
|
||||
{
|
||||
Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
Assert( m_memoryLists[index].lockCount == 0 );
|
||||
if ( m_memoryLists[index].lockCount )
|
||||
BreakLock( handle );
|
||||
m_memoryLists.Unlink( m_lruList, index );
|
||||
void *p = GetForFreeByIndex( index );
|
||||
Unlock();
|
||||
|
||||
DestroyResourceStorage( p );
|
||||
}
|
||||
|
||||
|
||||
void *CDataManagerBase::LockResource( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lruList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lockList, memoryIndex );
|
||||
}
|
||||
Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1);
|
||||
m_memoryLists[memoryIndex].lockCount++;
|
||||
return m_memoryLists[memoryIndex].pStore;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CDataManagerBase::UnlockResource( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
Assert( m_memoryLists[memoryIndex].lockCount > 0 );
|
||||
if ( m_memoryLists[memoryIndex].lockCount > 0 )
|
||||
{
|
||||
m_memoryLists[memoryIndex].lockCount--;
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lockList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
|
||||
}
|
||||
}
|
||||
return m_memoryLists[memoryIndex].lockCount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
return m_memoryLists[memoryIndex].pStore;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void *CDataManagerBase::GetResource_NoLock( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
TouchByIndex( memoryIndex );
|
||||
return m_memoryLists[memoryIndex].pStore;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CDataManagerBase::TouchResource( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
TouchByIndex( FromHandle(handle) );
|
||||
}
|
||||
|
||||
void CDataManagerBase::MarkAsStale( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lruList, memoryIndex );
|
||||
m_memoryLists.LinkToHead( m_lruList, memoryIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CDataManagerBase::BreakLock( memhandle_t handle )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
unsigned short memoryIndex = FromHandle(handle);
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount )
|
||||
{
|
||||
int nBroken = m_memoryLists[memoryIndex].lockCount;
|
||||
m_memoryLists[memoryIndex].lockCount = 0;
|
||||
m_memoryLists.Unlink( m_lockList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
|
||||
|
||||
return nBroken;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CDataManagerBase::BreakAllLocks()
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
int nBroken = 0;
|
||||
int node;
|
||||
int nextNode;
|
||||
|
||||
node = m_memoryLists.Head(m_lockList);
|
||||
while ( node != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
nBroken++;
|
||||
nextNode = m_memoryLists.Next(node);
|
||||
m_memoryLists[node].lockCount = 0;
|
||||
m_memoryLists.Unlink( m_lockList, node );
|
||||
m_memoryLists.LinkToTail( m_lruList, node );
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
return nBroken;
|
||||
|
||||
}
|
||||
|
||||
unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
int memoryIndex = m_memoryLists.Head(m_freeList);
|
||||
unsigned short list = ( bCreateLocked ) ? m_lockList : m_lruList;
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
m_memoryLists.Unlink( m_freeList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( list, memoryIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
memoryIndex = m_memoryLists.AddToTail( list );
|
||||
}
|
||||
|
||||
if ( bCreateLocked )
|
||||
{
|
||||
m_memoryLists[memoryIndex].lockCount++;
|
||||
}
|
||||
|
||||
return memoryIndex;
|
||||
}
|
||||
|
||||
memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize )
|
||||
{
|
||||
AUTO_LOCK_DM();
|
||||
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
|
||||
mem.pStore = pStore;
|
||||
m_memUsed += realSize;
|
||||
return ToHandle(memoryIndex);
|
||||
}
|
||||
|
||||
void CDataManagerBase::TouchByIndex( unsigned short memoryIndex )
|
||||
{
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
if ( m_memoryLists[memoryIndex].lockCount == 0 )
|
||||
{
|
||||
m_memoryLists.Unlink( m_lruList, memoryIndex );
|
||||
m_memoryLists.LinkToTail( m_lruList, memoryIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memhandle_t CDataManagerBase::ToHandle( unsigned short index )
|
||||
{
|
||||
unsigned int hiword = m_memoryLists.Element(index).serial;
|
||||
hiword <<= 16;
|
||||
index++;
|
||||
return (memhandle_t)( hiword|index );
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::TargetSize()
|
||||
{
|
||||
return MemTotal_Inline();
|
||||
}
|
||||
|
||||
unsigned int CDataManagerBase::AvailableSize()
|
||||
{
|
||||
return MemAvailable_Inline();
|
||||
}
|
||||
|
||||
|
||||
unsigned int CDataManagerBase::UsedSize()
|
||||
{
|
||||
return MemUsed_Inline();
|
||||
}
|
||||
|
||||
// free resources until there is enough space to hold "size"
|
||||
unsigned int CDataManagerBase::EnsureCapacity( unsigned int size )
|
||||
{
|
||||
unsigned nBytesInitial = MemUsed_Inline();
|
||||
while ( MemUsed_Inline() > MemTotal_Inline() || MemAvailable_Inline() < size )
|
||||
{
|
||||
Lock();
|
||||
int lruIndex = m_memoryLists.Head( m_lruList );
|
||||
if ( lruIndex == m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
Unlock();
|
||||
break;
|
||||
}
|
||||
m_memoryLists.Unlink( m_lruList, lruIndex );
|
||||
void *p = GetForFreeByIndex( lruIndex );
|
||||
Unlock();
|
||||
DestroyResourceStorage( p );
|
||||
}
|
||||
return ( nBytesInitial - MemUsed_Inline() );
|
||||
}
|
||||
|
||||
// free this resource and move the handle to the free list
|
||||
void *CDataManagerBase::GetForFreeByIndex( unsigned short memoryIndex )
|
||||
{
|
||||
void *p = NULL;
|
||||
if ( memoryIndex != m_memoryLists.InvalidIndex() )
|
||||
{
|
||||
Assert( m_memoryLists[memoryIndex].lockCount == 0 );
|
||||
|
||||
resource_lru_element_t &mem = m_memoryLists[memoryIndex];
|
||||
unsigned size = GetRealSize( mem.pStore );
|
||||
if ( size > m_memUsed )
|
||||
{
|
||||
ExecuteOnce( Warning( "Data manager 'used' memory incorrect\n" ) );
|
||||
size = m_memUsed;
|
||||
}
|
||||
m_memUsed -= size;
|
||||
p = mem.pStore;
|
||||
mem.pStore = NULL;
|
||||
mem.serial++;
|
||||
m_memoryLists.LinkToTail( m_freeList, memoryIndex );
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// get a list of everything in the LRU
|
||||
void CDataManagerBase::GetLRUHandleList( CUtlVector< memhandle_t >& list )
|
||||
{
|
||||
for ( int node = m_memoryLists.Tail(m_lruList);
|
||||
node != m_memoryLists.InvalidIndex();
|
||||
node = m_memoryLists.Previous(node) )
|
||||
{
|
||||
list.AddToTail( ToHandle( node ) );
|
||||
}
|
||||
}
|
||||
|
||||
// get a list of everything locked
|
||||
void CDataManagerBase::GetLockHandleList( CUtlVector< memhandle_t >& list )
|
||||
{
|
||||
for ( int node = m_memoryLists.Head(m_lockList);
|
||||
node != m_memoryLists.InvalidIndex();
|
||||
node = m_memoryLists.Next(node) )
|
||||
{
|
||||
list.AddToTail( ToHandle( node ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,497 +1,497 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A collection of utility classes to simplify file I/O, and
|
||||
// as much as possible contain portability problems. Here avoiding
|
||||
// including windows.h.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0502 // ReadDirectoryChangesW
|
||||
#endif
|
||||
|
||||
#if defined(OSX)
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#define ASYNC_FILEIO
|
||||
#if defined( LINUX )
|
||||
// Linux hasn't got a good AIO library that we have found yet, so lets punt for now
|
||||
#undef ASYNC_FILEIO
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
//#include <direct.h>
|
||||
#include <io.h>
|
||||
// unset to force to use stdio implementation
|
||||
#define WIN32_FILEIO
|
||||
|
||||
#if defined(ASYNC_FILEIO)
|
||||
#if defined(_WIN32) && !defined(WIN32_FILEIO)
|
||||
#error "trying to use async io without win32 filesystem API usage, that isn't doable"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else /* not defined (_WIN32) */
|
||||
#include <utime.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h> // for unlink
|
||||
#include <limits.h> // defines PATH_MAX
|
||||
#include <alloca.h> // 'cause we like smashing the stack
|
||||
#if defined( _PS3 )
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#include <sched.h>
|
||||
#define int64 int64_t
|
||||
|
||||
#define _A_SUBDIR S_IFDIR
|
||||
|
||||
// FUTURE map _A_HIDDEN via checking filename against .*
|
||||
#define _A_HIDDEN 0
|
||||
|
||||
// FUTURE check 'read only' by checking mode against S_IRUSR
|
||||
#define _A_RDONLY 0
|
||||
|
||||
// no files under posix are 'system' or 'archive'
|
||||
#define _A_SYSTEM 0
|
||||
#define _A_ARCH 0
|
||||
|
||||
#endif
|
||||
|
||||
#include "tier1/fileio.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include <errno.h>
|
||||
|
||||
#if defined( WIN32_FILEIO )
|
||||
#include "winlite.h"
|
||||
#endif
|
||||
|
||||
#if defined( ASYNC_FILEIO )
|
||||
#ifdef _WIN32
|
||||
#include "winlite.h"
|
||||
#elif defined(_PS3)
|
||||
// bugbug ps3 - see some aio files under libfs.. skipping for the moment
|
||||
#elif defined(POSIX)
|
||||
#include <aio.h>
|
||||
#else
|
||||
#error "aio please"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor from UTF8
|
||||
//-----------------------------------------------------------------------------
|
||||
CPathString::CPathString( const char *pchUTF8Path )
|
||||
{
|
||||
// Need to first turn into an absolute path, so \\?\ pre-pended paths will be ok
|
||||
m_pchUTF8Path = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
|
||||
m_pwchWideCharPathPrepended = NULL;
|
||||
|
||||
// First, convert to absolute path, which also does Q_FixSlashes for us.
|
||||
Q_MakeAbsolutePath( m_pchUTF8Path, MAX_UNICODE_PATH * 4, pchUTF8Path );
|
||||
|
||||
// Second, fix any double slashes
|
||||
V_FixDoubleSlashes( m_pchUTF8Path );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CPathString::~CPathString()
|
||||
{
|
||||
if ( m_pwchWideCharPathPrepended )
|
||||
{
|
||||
delete[] m_pwchWideCharPathPrepended;
|
||||
m_pwchWideCharPathPrepended = NULL;
|
||||
}
|
||||
|
||||
if ( m_pchUTF8Path )
|
||||
{
|
||||
delete[] m_pchUTF8Path;
|
||||
m_pchUTF8Path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Access UTF8 path
|
||||
//-----------------------------------------------------------------------------
|
||||
const char * CPathString::GetUTF8Path()
|
||||
{
|
||||
return m_pchUTF8Path;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets wchar_t based path, with \\?\ pre-pended (allowing long paths
|
||||
// on Win32, should only be used with unicode extended path aware filesystem calls)
|
||||
//-----------------------------------------------------------------------------
|
||||
const wchar_t *CPathString::GetWCharPathPrePended()
|
||||
{
|
||||
PopulateWCharPath();
|
||||
return m_pwchWideCharPathPrepended;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Builds wchar path string
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPathString::PopulateWCharPath()
|
||||
{
|
||||
if ( m_pwchWideCharPathPrepended )
|
||||
return;
|
||||
|
||||
// Check if the UTF8 path starts with \\, which on Win32 means it's a UNC path, and then needs a different prefix
|
||||
if ( m_pchUTF8Path[0] == '\\' && m_pchUTF8Path[1] == '\\' )
|
||||
{
|
||||
m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+8];
|
||||
Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\UNC\\", 8*sizeof(wchar_t) );
|
||||
#ifdef DBGFLAG_ASSERT
|
||||
int cchResult =
|
||||
#endif
|
||||
Q_UTF8ToUnicode( m_pchUTF8Path+2, m_pwchWideCharPathPrepended+8, MAX_UNICODE_PATH*sizeof(wchar_t) );
|
||||
Assert( cchResult );
|
||||
|
||||
// Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
|
||||
m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+7] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+4];
|
||||
Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\", 4*sizeof(wchar_t) );
|
||||
#ifdef DBGFLAG_ASSERT
|
||||
int cchResult =
|
||||
#endif
|
||||
Q_UTF8ToUnicode( m_pchUTF8Path, m_pwchWideCharPathPrepended+4, MAX_UNICODE_PATH*sizeof(wchar_t) );
|
||||
Assert( cchResult );
|
||||
|
||||
// Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
|
||||
m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
struct DirWatcherOverlapped : public OVERLAPPED
|
||||
{
|
||||
CDirWatcher *m_pDirWatcher;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(_PS3) && !defined(_X360)
|
||||
// a buffer full of file names
|
||||
static const int k_cubDirWatchBufferSize = 8 * 1024;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: directory watching
|
||||
//-----------------------------------------------------------------------------
|
||||
CDirWatcher::CDirWatcher()
|
||||
{
|
||||
m_hFile = NULL;
|
||||
m_pOverlapped = NULL;
|
||||
m_pFileInfo = NULL;
|
||||
#ifdef OSX
|
||||
m_WatcherStream = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: directory watching
|
||||
//-----------------------------------------------------------------------------
|
||||
CDirWatcher::~CDirWatcher()
|
||||
{
|
||||
#ifdef WIN32
|
||||
if ( m_pOverlapped )
|
||||
{
|
||||
// mark the overlapped structure as gone
|
||||
DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
|
||||
pDirWatcherOverlapped->m_pDirWatcher = NULL;
|
||||
}
|
||||
|
||||
if ( m_hFile )
|
||||
{
|
||||
// make sure we flush any pending I/O's on the handle
|
||||
::CancelIo( m_hFile );
|
||||
::SleepEx( 0, TRUE );
|
||||
// close the handle
|
||||
::CloseHandle( m_hFile );
|
||||
}
|
||||
#elif defined(OSX)
|
||||
if ( m_WatcherStream )
|
||||
{
|
||||
FSEventStreamStop( (FSEventStreamRef)m_WatcherStream );
|
||||
FSEventStreamInvalidate( (FSEventStreamRef)m_WatcherStream );
|
||||
FSEventStreamRelease( (FSEventStreamRef)m_WatcherStream );
|
||||
m_WatcherStream = 0;
|
||||
}
|
||||
#endif
|
||||
if ( m_pFileInfo )
|
||||
{
|
||||
free( m_pFileInfo );
|
||||
}
|
||||
if ( m_pOverlapped )
|
||||
{
|
||||
free( m_pOverlapped );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: callback watch
|
||||
// gets called on the same thread whenever a SleepEx() occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
class CDirWatcherFriend
|
||||
{
|
||||
public:
|
||||
static void WINAPI DirWatchCallback( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED *pOverlapped )
|
||||
{
|
||||
DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)pOverlapped;
|
||||
|
||||
// see if we've been cancelled
|
||||
if ( !pDirWatcherOverlapped->m_pDirWatcher )
|
||||
return;
|
||||
|
||||
// parse and pass back
|
||||
if ( dwNumberOfBytesTransfered > sizeof(FILE_NOTIFY_INFORMATION) )
|
||||
{
|
||||
FILE_NOTIFY_INFORMATION *pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)pDirWatcherOverlapped->m_pDirWatcher->m_pFileInfo;
|
||||
do
|
||||
{
|
||||
// null terminate the string and turn it to UTF-8
|
||||
int cNumWChars = pFileNotifyInformation->FileNameLength / sizeof(wchar_t);
|
||||
wchar_t *pwchT = new wchar_t[cNumWChars + 1];
|
||||
memcpy( pwchT, pFileNotifyInformation->FileName, pFileNotifyInformation->FileNameLength );
|
||||
pwchT[cNumWChars] = 0;
|
||||
CStrAutoEncode strAutoEncode( pwchT );
|
||||
|
||||
// add it to our list
|
||||
pDirWatcherOverlapped->m_pDirWatcher->AddFileToChangeList( strAutoEncode.ToString() );
|
||||
delete[] pwchT;
|
||||
if ( pFileNotifyInformation->NextEntryOffset == 0 )
|
||||
break;
|
||||
|
||||
// move to the next file
|
||||
pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)(((byte*)pFileNotifyInformation) + pFileNotifyInformation->NextEntryOffset);
|
||||
} while ( 1 );
|
||||
}
|
||||
|
||||
|
||||
// watch again
|
||||
pDirWatcherOverlapped->m_pDirWatcher->PostDirWatch();
|
||||
}
|
||||
};
|
||||
#elif defined(OSX)
|
||||
void CheckDirectoryForChanges( const char *path_buff, CDirWatcher *pDirWatch, bool bRecurse )
|
||||
{
|
||||
DIR *dir = opendir(path_buff);
|
||||
char fullpath[MAX_PATH];
|
||||
struct dirent *dirent;
|
||||
struct timespec ts = { 0, 0 };
|
||||
bool bTimeSet = false;
|
||||
|
||||
while ( (dirent = readdir(dir)) != NULL )
|
||||
{
|
||||
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
snprintf( fullpath, PATH_MAX, "%s/%s", path_buff, dirent->d_name );
|
||||
|
||||
struct stat st;
|
||||
if (lstat(fullpath, &st) != 0)
|
||||
continue;
|
||||
|
||||
if ( S_ISDIR(st.st_mode) && bRecurse )
|
||||
{
|
||||
CheckDirectoryForChanges( fullpath, pDirWatch, bRecurse );
|
||||
}
|
||||
else if ( st.st_mtimespec.tv_sec > pDirWatch->m_modTime.tv_sec ||
|
||||
( st.st_mtimespec.tv_sec == pDirWatch->m_modTime.tv_sec && st.st_mtimespec.tv_nsec > pDirWatch->m_modTime.tv_nsec ) )
|
||||
{
|
||||
ts = st.st_mtimespec;
|
||||
bTimeSet = true;
|
||||
// the win32 size only sends up the dir relative to the watching dir, so replicate that here
|
||||
pDirWatch->AddFileToChangeList( fullpath + pDirWatch->m_BaseDir.Length() + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( bTimeSet )
|
||||
pDirWatch->m_modTime = ts;
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void fsevents_callback( ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents,void *eventPaths,
|
||||
const FSEventStreamEventFlags eventMasks[], const FSEventStreamEventId eventIDs[] )
|
||||
{
|
||||
char path_buff[PATH_MAX];
|
||||
for (int i=0; i < numEvents; i++)
|
||||
{
|
||||
char **paths = (char **)eventPaths;
|
||||
|
||||
strcpy(path_buff, paths[i]);
|
||||
int len = strlen(path_buff);
|
||||
if (path_buff[len-1] == '/')
|
||||
{
|
||||
// chop off a trailing slash
|
||||
path_buff[--len] = '\0';
|
||||
}
|
||||
|
||||
bool bRecurse = false;
|
||||
|
||||
if (eventMasks[i] & kFSEventStreamEventFlagMustScanSubDirs
|
||||
|| eventMasks[i] & kFSEventStreamEventFlagUserDropped
|
||||
|| eventMasks[i] & kFSEventStreamEventFlagKernelDropped)
|
||||
{
|
||||
bRecurse = true;
|
||||
}
|
||||
|
||||
CDirWatcher *pDirWatch = (CDirWatcher *)clientCallBackInfo;
|
||||
// make sure its in our subdir
|
||||
if ( !V_strnicmp( path_buff, pDirWatch->m_BaseDir.String(), pDirWatch->m_BaseDir.Length() ) )
|
||||
CheckDirectoryForChanges( path_buff, pDirWatch, bRecurse );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: only one directory can be watched at a time
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDirWatcher::SetDirToWatch( const char *pchDir )
|
||||
{
|
||||
if ( !pchDir || !*pchDir )
|
||||
return;
|
||||
|
||||
CPathString strPath( pchDir );
|
||||
#ifdef WIN32
|
||||
// open the directory
|
||||
m_hFile = ::CreateFileW( strPath.GetWCharPathPrePended(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, NULL );
|
||||
|
||||
// create our buffers
|
||||
m_pFileInfo = malloc( k_cubDirWatchBufferSize );
|
||||
m_pOverlapped = malloc( sizeof( DirWatcherOverlapped ) );
|
||||
|
||||
// post a watch
|
||||
PostDirWatch();
|
||||
#elif defined(OSX)
|
||||
CFStringRef mypath = CFStringCreateWithCString( NULL, strPath.GetUTF8Path(), kCFStringEncodingMacRoman );
|
||||
if ( !mypath )
|
||||
{
|
||||
Assert( !"Failed to CFStringCreateWithCString watcher path" );
|
||||
return;
|
||||
}
|
||||
|
||||
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
|
||||
FSEventStreamContext callbackInfo = {0, this, NULL, NULL, NULL};
|
||||
CFAbsoluteTime latency = 1.0; // Latency in seconds
|
||||
|
||||
m_WatcherStream = (void *)FSEventStreamCreate(NULL,
|
||||
&fsevents_callback,
|
||||
&callbackInfo,
|
||||
pathsToWatch,
|
||||
kFSEventStreamEventIdSinceNow,
|
||||
latency,
|
||||
kFSEventStreamCreateFlagNoDefer
|
||||
);
|
||||
|
||||
FSEventStreamScheduleWithRunLoop( (FSEventStreamRef)m_WatcherStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
CFRelease(pathsToWatch );
|
||||
CFRelease( mypath );
|
||||
|
||||
FSEventStreamStart( (FSEventStreamRef)m_WatcherStream );
|
||||
|
||||
char szFullPath[MAX_PATH];
|
||||
Q_MakeAbsolutePath( szFullPath, sizeof(szFullPath), pchDir );
|
||||
m_BaseDir = szFullPath;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday( &tv, NULL );
|
||||
TIMEVAL_TO_TIMESPEC( &tv, &m_modTime );
|
||||
|
||||
#else
|
||||
Assert( !"Impl me" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: used by callback functions to push a file onto the list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDirWatcher::PostDirWatch()
|
||||
{
|
||||
memset( m_pOverlapped, 0, sizeof(DirWatcherOverlapped) );
|
||||
DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
|
||||
pDirWatcherOverlapped->m_pDirWatcher = this;
|
||||
|
||||
DWORD dwBytes;
|
||||
::ReadDirectoryChangesW( m_hFile, m_pFileInfo, k_cubDirWatchBufferSize, TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME, &dwBytes, (OVERLAPPED *)m_pOverlapped, &CDirWatcherFriend::DirWatchCallback );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: used by callback functions to push a file onto the list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDirWatcher::AddFileToChangeList( const char *pchFile )
|
||||
{
|
||||
// make sure it isn't already in the list
|
||||
FOR_EACH_LL( m_listChangedFiles, i )
|
||||
{
|
||||
if ( !Q_stricmp( m_listChangedFiles[i], pchFile ) )
|
||||
return;
|
||||
}
|
||||
|
||||
m_listChangedFiles.AddToTail( pchFile );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: retrieve any changes
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CDirWatcher::GetChangedFile( CUtlString *psFile )
|
||||
{
|
||||
#ifdef WIN32
|
||||
// this will trigger any pending directory reads
|
||||
// this does get hit other places in the code; so the callback can happen at any time
|
||||
::SleepEx( 0, TRUE );
|
||||
#endif
|
||||
|
||||
if ( !m_listChangedFiles.Count() )
|
||||
return false;
|
||||
|
||||
*psFile = m_listChangedFiles[m_listChangedFiles.Head()];
|
||||
m_listChangedFiles.Remove( m_listChangedFiles.Head() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void CDirWatcher::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
VALIDATE_SCOPE();
|
||||
|
||||
validator.ClaimMemory( m_pOverlapped );
|
||||
validator.ClaimMemory( m_pFileInfo );
|
||||
ValidateObj( m_listChangedFiles );
|
||||
FOR_EACH_LL( m_listChangedFiles, i )
|
||||
{
|
||||
ValidateObj( m_listChangedFiles[i] );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A collection of utility classes to simplify file I/O, and
|
||||
// as much as possible contain portability problems. Here avoiding
|
||||
// including windows.h.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0502 // ReadDirectoryChangesW
|
||||
#endif
|
||||
|
||||
#if defined(OSX)
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#define ASYNC_FILEIO
|
||||
#if defined( LINUX )
|
||||
// Linux hasn't got a good AIO library that we have found yet, so lets punt for now
|
||||
#undef ASYNC_FILEIO
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
//#include <direct.h>
|
||||
#include <io.h>
|
||||
// unset to force to use stdio implementation
|
||||
#define WIN32_FILEIO
|
||||
|
||||
#if defined(ASYNC_FILEIO)
|
||||
#if defined(_WIN32) && !defined(WIN32_FILEIO)
|
||||
#error "trying to use async io without win32 filesystem API usage, that isn't doable"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else /* not defined (_WIN32) */
|
||||
#include <utime.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h> // for unlink
|
||||
#include <limits.h> // defines PATH_MAX
|
||||
#include <alloca.h> // 'cause we like smashing the stack
|
||||
#if defined( _PS3 )
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/statvfs.h>
|
||||
#endif
|
||||
#include <sched.h>
|
||||
#define int64 int64_t
|
||||
|
||||
#define _A_SUBDIR S_IFDIR
|
||||
|
||||
// FUTURE map _A_HIDDEN via checking filename against .*
|
||||
#define _A_HIDDEN 0
|
||||
|
||||
// FUTURE check 'read only' by checking mode against S_IRUSR
|
||||
#define _A_RDONLY 0
|
||||
|
||||
// no files under posix are 'system' or 'archive'
|
||||
#define _A_SYSTEM 0
|
||||
#define _A_ARCH 0
|
||||
|
||||
#endif
|
||||
|
||||
#include "tier1/fileio.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include <errno.h>
|
||||
|
||||
#if defined( WIN32_FILEIO )
|
||||
#include "winlite.h"
|
||||
#endif
|
||||
|
||||
#if defined( ASYNC_FILEIO )
|
||||
#ifdef _WIN32
|
||||
#include "winlite.h"
|
||||
#elif defined(_PS3)
|
||||
// bugbug ps3 - see some aio files under libfs.. skipping for the moment
|
||||
#elif defined(POSIX)
|
||||
#include <aio.h>
|
||||
#else
|
||||
#error "aio please"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor from UTF8
|
||||
//-----------------------------------------------------------------------------
|
||||
CPathString::CPathString( const char *pchUTF8Path )
|
||||
{
|
||||
// Need to first turn into an absolute path, so \\?\ pre-pended paths will be ok
|
||||
m_pchUTF8Path = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
|
||||
m_pwchWideCharPathPrepended = NULL;
|
||||
|
||||
// First, convert to absolute path, which also does Q_FixSlashes for us.
|
||||
Q_MakeAbsolutePath( m_pchUTF8Path, MAX_UNICODE_PATH * 4, pchUTF8Path );
|
||||
|
||||
// Second, fix any double slashes
|
||||
V_FixDoubleSlashes( m_pchUTF8Path );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CPathString::~CPathString()
|
||||
{
|
||||
if ( m_pwchWideCharPathPrepended )
|
||||
{
|
||||
delete[] m_pwchWideCharPathPrepended;
|
||||
m_pwchWideCharPathPrepended = NULL;
|
||||
}
|
||||
|
||||
if ( m_pchUTF8Path )
|
||||
{
|
||||
delete[] m_pchUTF8Path;
|
||||
m_pchUTF8Path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Access UTF8 path
|
||||
//-----------------------------------------------------------------------------
|
||||
const char * CPathString::GetUTF8Path()
|
||||
{
|
||||
return m_pchUTF8Path;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets wchar_t based path, with \\?\ pre-pended (allowing long paths
|
||||
// on Win32, should only be used with unicode extended path aware filesystem calls)
|
||||
//-----------------------------------------------------------------------------
|
||||
const wchar_t *CPathString::GetWCharPathPrePended()
|
||||
{
|
||||
PopulateWCharPath();
|
||||
return m_pwchWideCharPathPrepended;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Builds wchar path string
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPathString::PopulateWCharPath()
|
||||
{
|
||||
if ( m_pwchWideCharPathPrepended )
|
||||
return;
|
||||
|
||||
// Check if the UTF8 path starts with \\, which on Win32 means it's a UNC path, and then needs a different prefix
|
||||
if ( m_pchUTF8Path[0] == '\\' && m_pchUTF8Path[1] == '\\' )
|
||||
{
|
||||
m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+8];
|
||||
Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\UNC\\", 8*sizeof(wchar_t) );
|
||||
#ifdef DBGFLAG_ASSERT
|
||||
int cchResult =
|
||||
#endif
|
||||
Q_UTF8ToUnicode( m_pchUTF8Path+2, m_pwchWideCharPathPrepended+8, MAX_UNICODE_PATH*sizeof(wchar_t) );
|
||||
Assert( cchResult );
|
||||
|
||||
// Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
|
||||
m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+7] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pwchWideCharPathPrepended = new wchar_t[MAX_UNICODE_PATH+4];
|
||||
Q_memcpy( m_pwchWideCharPathPrepended, L"\\\\?\\", 4*sizeof(wchar_t) );
|
||||
#ifdef DBGFLAG_ASSERT
|
||||
int cchResult =
|
||||
#endif
|
||||
Q_UTF8ToUnicode( m_pchUTF8Path, m_pwchWideCharPathPrepended+4, MAX_UNICODE_PATH*sizeof(wchar_t) );
|
||||
Assert( cchResult );
|
||||
|
||||
// Be sure we NULL terminate within our allocated region incase Q_UTF8ToUnicode failed, though we're already in bad shape then.
|
||||
m_pwchWideCharPathPrepended[MAX_UNICODE_PATH+3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
struct DirWatcherOverlapped : public OVERLAPPED
|
||||
{
|
||||
CDirWatcher *m_pDirWatcher;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if !defined(_PS3) && !defined(_X360)
|
||||
// a buffer full of file names
|
||||
static const int k_cubDirWatchBufferSize = 8 * 1024;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: directory watching
|
||||
//-----------------------------------------------------------------------------
|
||||
CDirWatcher::CDirWatcher()
|
||||
{
|
||||
m_hFile = NULL;
|
||||
m_pOverlapped = NULL;
|
||||
m_pFileInfo = NULL;
|
||||
#ifdef OSX
|
||||
m_WatcherStream = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: directory watching
|
||||
//-----------------------------------------------------------------------------
|
||||
CDirWatcher::~CDirWatcher()
|
||||
{
|
||||
#ifdef WIN32
|
||||
if ( m_pOverlapped )
|
||||
{
|
||||
// mark the overlapped structure as gone
|
||||
DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
|
||||
pDirWatcherOverlapped->m_pDirWatcher = NULL;
|
||||
}
|
||||
|
||||
if ( m_hFile )
|
||||
{
|
||||
// make sure we flush any pending I/O's on the handle
|
||||
::CancelIo( m_hFile );
|
||||
::SleepEx( 0, TRUE );
|
||||
// close the handle
|
||||
::CloseHandle( m_hFile );
|
||||
}
|
||||
#elif defined(OSX)
|
||||
if ( m_WatcherStream )
|
||||
{
|
||||
FSEventStreamStop( (FSEventStreamRef)m_WatcherStream );
|
||||
FSEventStreamInvalidate( (FSEventStreamRef)m_WatcherStream );
|
||||
FSEventStreamRelease( (FSEventStreamRef)m_WatcherStream );
|
||||
m_WatcherStream = 0;
|
||||
}
|
||||
#endif
|
||||
if ( m_pFileInfo )
|
||||
{
|
||||
free( m_pFileInfo );
|
||||
}
|
||||
if ( m_pOverlapped )
|
||||
{
|
||||
free( m_pOverlapped );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: callback watch
|
||||
// gets called on the same thread whenever a SleepEx() occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
class CDirWatcherFriend
|
||||
{
|
||||
public:
|
||||
static void WINAPI DirWatchCallback( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED *pOverlapped )
|
||||
{
|
||||
DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)pOverlapped;
|
||||
|
||||
// see if we've been cancelled
|
||||
if ( !pDirWatcherOverlapped->m_pDirWatcher )
|
||||
return;
|
||||
|
||||
// parse and pass back
|
||||
if ( dwNumberOfBytesTransfered > sizeof(FILE_NOTIFY_INFORMATION) )
|
||||
{
|
||||
FILE_NOTIFY_INFORMATION *pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)pDirWatcherOverlapped->m_pDirWatcher->m_pFileInfo;
|
||||
do
|
||||
{
|
||||
// null terminate the string and turn it to UTF-8
|
||||
int cNumWChars = pFileNotifyInformation->FileNameLength / sizeof(wchar_t);
|
||||
wchar_t *pwchT = new wchar_t[cNumWChars + 1];
|
||||
memcpy( pwchT, pFileNotifyInformation->FileName, pFileNotifyInformation->FileNameLength );
|
||||
pwchT[cNumWChars] = 0;
|
||||
CStrAutoEncode strAutoEncode( pwchT );
|
||||
|
||||
// add it to our list
|
||||
pDirWatcherOverlapped->m_pDirWatcher->AddFileToChangeList( strAutoEncode.ToString() );
|
||||
delete[] pwchT;
|
||||
if ( pFileNotifyInformation->NextEntryOffset == 0 )
|
||||
break;
|
||||
|
||||
// move to the next file
|
||||
pFileNotifyInformation = (FILE_NOTIFY_INFORMATION *)(((byte*)pFileNotifyInformation) + pFileNotifyInformation->NextEntryOffset);
|
||||
} while ( 1 );
|
||||
}
|
||||
|
||||
|
||||
// watch again
|
||||
pDirWatcherOverlapped->m_pDirWatcher->PostDirWatch();
|
||||
}
|
||||
};
|
||||
#elif defined(OSX)
|
||||
void CheckDirectoryForChanges( const char *path_buff, CDirWatcher *pDirWatch, bool bRecurse )
|
||||
{
|
||||
DIR *dir = opendir(path_buff);
|
||||
char fullpath[MAX_PATH];
|
||||
struct dirent *dirent;
|
||||
struct timespec ts = { 0, 0 };
|
||||
bool bTimeSet = false;
|
||||
|
||||
while ( (dirent = readdir(dir)) != NULL )
|
||||
{
|
||||
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
snprintf( fullpath, PATH_MAX, "%s/%s", path_buff, dirent->d_name );
|
||||
|
||||
struct stat st;
|
||||
if (lstat(fullpath, &st) != 0)
|
||||
continue;
|
||||
|
||||
if ( S_ISDIR(st.st_mode) && bRecurse )
|
||||
{
|
||||
CheckDirectoryForChanges( fullpath, pDirWatch, bRecurse );
|
||||
}
|
||||
else if ( st.st_mtimespec.tv_sec > pDirWatch->m_modTime.tv_sec ||
|
||||
( st.st_mtimespec.tv_sec == pDirWatch->m_modTime.tv_sec && st.st_mtimespec.tv_nsec > pDirWatch->m_modTime.tv_nsec ) )
|
||||
{
|
||||
ts = st.st_mtimespec;
|
||||
bTimeSet = true;
|
||||
// the win32 size only sends up the dir relative to the watching dir, so replicate that here
|
||||
pDirWatch->AddFileToChangeList( fullpath + pDirWatch->m_BaseDir.Length() + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( bTimeSet )
|
||||
pDirWatch->m_modTime = ts;
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void fsevents_callback( ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents,void *eventPaths,
|
||||
const FSEventStreamEventFlags eventMasks[], const FSEventStreamEventId eventIDs[] )
|
||||
{
|
||||
char path_buff[PATH_MAX];
|
||||
for (int i=0; i < numEvents; i++)
|
||||
{
|
||||
char **paths = (char **)eventPaths;
|
||||
|
||||
strcpy(path_buff, paths[i]);
|
||||
int len = strlen(path_buff);
|
||||
if (path_buff[len-1] == '/')
|
||||
{
|
||||
// chop off a trailing slash
|
||||
path_buff[--len] = '\0';
|
||||
}
|
||||
|
||||
bool bRecurse = false;
|
||||
|
||||
if (eventMasks[i] & kFSEventStreamEventFlagMustScanSubDirs
|
||||
|| eventMasks[i] & kFSEventStreamEventFlagUserDropped
|
||||
|| eventMasks[i] & kFSEventStreamEventFlagKernelDropped)
|
||||
{
|
||||
bRecurse = true;
|
||||
}
|
||||
|
||||
CDirWatcher *pDirWatch = (CDirWatcher *)clientCallBackInfo;
|
||||
// make sure its in our subdir
|
||||
if ( !V_strnicmp( path_buff, pDirWatch->m_BaseDir.String(), pDirWatch->m_BaseDir.Length() ) )
|
||||
CheckDirectoryForChanges( path_buff, pDirWatch, bRecurse );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: only one directory can be watched at a time
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDirWatcher::SetDirToWatch( const char *pchDir )
|
||||
{
|
||||
if ( !pchDir || !*pchDir )
|
||||
return;
|
||||
|
||||
CPathString strPath( pchDir );
|
||||
#ifdef WIN32
|
||||
// open the directory
|
||||
m_hFile = ::CreateFileW( strPath.GetWCharPathPrePended(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_BACKUP_SEMANTICS, NULL );
|
||||
|
||||
// create our buffers
|
||||
m_pFileInfo = malloc( k_cubDirWatchBufferSize );
|
||||
m_pOverlapped = malloc( sizeof( DirWatcherOverlapped ) );
|
||||
|
||||
// post a watch
|
||||
PostDirWatch();
|
||||
#elif defined(OSX)
|
||||
CFStringRef mypath = CFStringCreateWithCString( NULL, strPath.GetUTF8Path(), kCFStringEncodingMacRoman );
|
||||
if ( !mypath )
|
||||
{
|
||||
Assert( !"Failed to CFStringCreateWithCString watcher path" );
|
||||
return;
|
||||
}
|
||||
|
||||
CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
|
||||
FSEventStreamContext callbackInfo = {0, this, NULL, NULL, NULL};
|
||||
CFAbsoluteTime latency = 1.0; // Latency in seconds
|
||||
|
||||
m_WatcherStream = (void *)FSEventStreamCreate(NULL,
|
||||
&fsevents_callback,
|
||||
&callbackInfo,
|
||||
pathsToWatch,
|
||||
kFSEventStreamEventIdSinceNow,
|
||||
latency,
|
||||
kFSEventStreamCreateFlagNoDefer
|
||||
);
|
||||
|
||||
FSEventStreamScheduleWithRunLoop( (FSEventStreamRef)m_WatcherStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
CFRelease(pathsToWatch );
|
||||
CFRelease( mypath );
|
||||
|
||||
FSEventStreamStart( (FSEventStreamRef)m_WatcherStream );
|
||||
|
||||
char szFullPath[MAX_PATH];
|
||||
Q_MakeAbsolutePath( szFullPath, sizeof(szFullPath), pchDir );
|
||||
m_BaseDir = szFullPath;
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday( &tv, NULL );
|
||||
TIMEVAL_TO_TIMESPEC( &tv, &m_modTime );
|
||||
|
||||
#else
|
||||
Assert( !"Impl me" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: used by callback functions to push a file onto the list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDirWatcher::PostDirWatch()
|
||||
{
|
||||
memset( m_pOverlapped, 0, sizeof(DirWatcherOverlapped) );
|
||||
DirWatcherOverlapped *pDirWatcherOverlapped = (DirWatcherOverlapped *)m_pOverlapped;
|
||||
pDirWatcherOverlapped->m_pDirWatcher = this;
|
||||
|
||||
DWORD dwBytes;
|
||||
::ReadDirectoryChangesW( m_hFile, m_pFileInfo, k_cubDirWatchBufferSize, TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME, &dwBytes, (OVERLAPPED *)m_pOverlapped, &CDirWatcherFriend::DirWatchCallback );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: used by callback functions to push a file onto the list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CDirWatcher::AddFileToChangeList( const char *pchFile )
|
||||
{
|
||||
// make sure it isn't already in the list
|
||||
FOR_EACH_LL( m_listChangedFiles, i )
|
||||
{
|
||||
if ( !Q_stricmp( m_listChangedFiles[i], pchFile ) )
|
||||
return;
|
||||
}
|
||||
|
||||
m_listChangedFiles.AddToTail( pchFile );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: retrieve any changes
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CDirWatcher::GetChangedFile( CUtlString *psFile )
|
||||
{
|
||||
#ifdef WIN32
|
||||
// this will trigger any pending directory reads
|
||||
// this does get hit other places in the code; so the callback can happen at any time
|
||||
::SleepEx( 0, TRUE );
|
||||
#endif
|
||||
|
||||
if ( !m_listChangedFiles.Count() )
|
||||
return false;
|
||||
|
||||
*psFile = m_listChangedFiles[m_listChangedFiles.Head()];
|
||||
m_listChangedFiles.Remove( m_listChangedFiles.Head() );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void CDirWatcher::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
VALIDATE_SCOPE();
|
||||
|
||||
validator.ClaimMemory( m_pOverlapped );
|
||||
validator.ClaimMemory( m_pFileInfo );
|
||||
ValidateObj( m_listChangedFiles );
|
||||
FOR_EACH_LL( m_listChangedFiles, i )
|
||||
{
|
||||
ValidateObj( m_listChangedFiles[i] );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _PS3 || _X360
|
||||
@@ -1,437 +1,437 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Variant Pearson Hash general purpose hashing algorithm described
|
||||
// by Cargill in C++ Report 1994. Generates a 16-bit result.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "tier0/basetypes.h"
|
||||
#include "tier0/platform.h"
|
||||
#include "generichash.h"
|
||||
#include <ctype.h>
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Table of randomly shuffled values from 0-255 generated by:
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
void MakeRandomValues()
|
||||
{
|
||||
int i, j, r;
|
||||
unsigned t;
|
||||
srand( 0xdeadbeef );
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
g_nRandomValues[i] = (unsigned )i;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
r = rand() & 0xff;
|
||||
t = g_nRandomValues[i];
|
||||
g_nRandomValues[i] = g_nRandomValues[r];
|
||||
g_nRandomValues[r] = t;
|
||||
}
|
||||
}
|
||||
|
||||
printf("static unsigned g_nRandomValues[256] =\n{\n");
|
||||
|
||||
for (i = 0; i < 256; i += 16)
|
||||
{
|
||||
printf("\t");
|
||||
for (j = 0; j < 16; j++)
|
||||
printf(" %3d,", g_nRandomValues[i+j]);
|
||||
printf("\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
*/
|
||||
|
||||
static unsigned g_nRandomValues[256] =
|
||||
{
|
||||
238, 164, 191, 168, 115, 16, 142, 11, 213, 214, 57, 151, 248, 252, 26, 198,
|
||||
13, 105, 102, 25, 43, 42, 227, 107, 210, 251, 86, 66, 83, 193, 126, 108,
|
||||
131, 3, 64, 186, 192, 81, 37, 158, 39, 244, 14, 254, 75, 30, 2, 88,
|
||||
172, 176, 255, 69, 0, 45, 116, 139, 23, 65, 183, 148, 33, 46, 203, 20,
|
||||
143, 205, 60, 197, 118, 9, 171, 51, 233, 135, 220, 49, 71, 184, 82, 109,
|
||||
36, 161, 169, 150, 63, 96, 173, 125, 113, 67, 224, 78, 232, 215, 35, 219,
|
||||
79, 181, 41, 229, 149, 153, 111, 217, 21, 72, 120, 163, 133, 40, 122, 140,
|
||||
208, 231, 211, 200, 160, 182, 104, 110, 178, 237, 15, 101, 27, 50, 24, 189,
|
||||
177, 130, 187, 92, 253, 136, 100, 212, 19, 174, 70, 22, 170, 206, 162, 74,
|
||||
247, 5, 47, 32, 179, 117, 132, 195, 124, 123, 245, 128, 236, 223, 12, 84,
|
||||
54, 218, 146, 228, 157, 94, 106, 31, 17, 29, 194, 34, 56, 134, 239, 246,
|
||||
241, 216, 127, 98, 7, 204, 154, 152, 209, 188, 48, 61, 87, 97, 225, 85,
|
||||
90, 167, 155, 112, 145, 114, 141, 93, 250, 4, 201, 156, 38, 89, 226, 196,
|
||||
1, 235, 44, 180, 159, 121, 119, 166, 190, 144, 10, 91, 76, 230, 221, 80,
|
||||
207, 55, 58, 53, 175, 8, 6, 52, 68, 242, 18, 222, 103, 249, 147, 129,
|
||||
138, 243, 28, 185, 62, 59, 240, 202, 234, 99, 77, 73, 199, 137, 95, 165,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// String
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashString( const char *pszKey )
|
||||
{
|
||||
const uint8 *k = (const uint8 *)pszKey;
|
||||
unsigned even = 0,
|
||||
odd = 0,
|
||||
n;
|
||||
|
||||
while ((n = *k++) != 0)
|
||||
{
|
||||
even = g_nRandomValues[odd ^ n];
|
||||
if ((n = *k++) != 0)
|
||||
odd = g_nRandomValues[even ^ n];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (even << 8) | odd ;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Case-insensitive string
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashStringCaseless( const char *pszKey )
|
||||
{
|
||||
const uint8 *k = (const uint8 *) pszKey;
|
||||
unsigned even = 0,
|
||||
odd = 0,
|
||||
n;
|
||||
|
||||
while ((n = toupper(*k++)) != 0)
|
||||
{
|
||||
even = g_nRandomValues[odd ^ n];
|
||||
if ((n = toupper(*k++)) != 0)
|
||||
odd = g_nRandomValues[even ^ n];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 32 bit conventional case-insensitive string
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashStringCaselessConventional( const char *pszKey )
|
||||
{
|
||||
unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add
|
||||
|
||||
for( ; *pszKey ; pszKey++ )
|
||||
{
|
||||
hash = ( ( hash << 5 ) + hash ) + (uint8)tolower(*pszKey);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// int hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashInt( const int n )
|
||||
{
|
||||
register unsigned even, odd;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 4-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash4( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 8-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash8( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+1);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 12-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash12( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+1);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+2);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 16-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash16( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+1);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+2);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+3);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Arbitrary fixed length hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashBlock( const void *pKey, unsigned size )
|
||||
{
|
||||
const uint8 * k = (const uint8 *) pKey;
|
||||
unsigned even = 0,
|
||||
odd = 0,
|
||||
n;
|
||||
|
||||
while (size)
|
||||
{
|
||||
--size;
|
||||
n = *k++;
|
||||
even = g_nRandomValues[odd ^ n];
|
||||
if (size)
|
||||
{
|
||||
--size;
|
||||
n = *k++;
|
||||
odd = g_nRandomValues[even ^ n];
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Murmur hash
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 MurmurHash2( const void * key, int len, uint32 seed )
|
||||
{
|
||||
// 'm' and 'r' are mixing constants generated offline.
|
||||
// They're not really 'magic', they just happen to work well.
|
||||
|
||||
const uint32 m = 0x5bd1e995;
|
||||
const int r = 24;
|
||||
|
||||
// Initialize the hash to a 'random' value
|
||||
|
||||
uint32 h = seed ^ len;
|
||||
|
||||
// Mix 4 bytes at a time into the hash
|
||||
|
||||
const unsigned char * data = (const unsigned char *)key;
|
||||
|
||||
while(len >= 4)
|
||||
{
|
||||
uint32 k = LittleDWord( *(uint32 *)data );
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h *= m;
|
||||
h ^= k;
|
||||
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
// Handle the last few bytes of the input array
|
||||
|
||||
switch(len)
|
||||
{
|
||||
case 3: h ^= data[2] << 16;
|
||||
case 2: h ^= data[1] << 8;
|
||||
case 1: h ^= data[0];
|
||||
h *= m;
|
||||
};
|
||||
|
||||
// Do a few final mixes of the hash to ensure the last few
|
||||
// bytes are well-incorporated.
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
#define TOLOWERU( c ) ( ( uint32 ) ( ( ( c >= 'A' ) && ( c <= 'Z' ) )? c + 32 : c ) )
|
||||
uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed )
|
||||
{
|
||||
int nLen = strlen( pString );
|
||||
char *p = ( char * ) stackalloc( nLen + 1 );
|
||||
for( int i = 0; i < nLen ; i++ )
|
||||
{
|
||||
p[i] = TOLOWERU( pString[i] );
|
||||
}
|
||||
return MurmurHash2( p, nLen, nSeed );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Murmur hash, 64 bit- endian neutral
|
||||
//-----------------------------------------------------------------------------
|
||||
uint64 MurmurHash64( const void * key, int len, uint32 seed )
|
||||
{
|
||||
// 'm' and 'r' are mixing constants generated offline.
|
||||
// They're not really 'magic', they just happen to work well.
|
||||
|
||||
const uint32 m = 0x5bd1e995;
|
||||
const int r = 24;
|
||||
|
||||
// Initialize the hash to a 'random' value
|
||||
|
||||
uint32 h1 = seed ^ len;
|
||||
uint32 h2 = 0;
|
||||
|
||||
// Mix 4 bytes at a time into the hash
|
||||
|
||||
const uint32 * data = (const uint32 *)key;
|
||||
while ( len >= 8 )
|
||||
{
|
||||
uint32 k1 = LittleDWord( *data++ );
|
||||
k1 *= m; k1 ^= k1 >> r; k1 *= m;
|
||||
h1 *= m; h1 ^= k1;
|
||||
len -= 4;
|
||||
|
||||
uint32 k2 = LittleDWord( *data++ );
|
||||
k2 *= m; k2 ^= k2 >> r; k2 *= m;
|
||||
h2 *= m; h2 ^= k2;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if(len >= 4)
|
||||
{
|
||||
uint32 k1 = LittleDWord( *data++ );
|
||||
k1 *= m; k1 ^= k1 >> r; k1 *= m;
|
||||
h1 *= m; h1 ^= k1;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
// Handle the last few bytes of the input array
|
||||
switch(len)
|
||||
{
|
||||
case 3: h2 ^= ((uint8*)data)[2] << 16;
|
||||
case 2: h2 ^= ((uint8*)data)[1] << 8;
|
||||
case 1: h2 ^= ((uint8*)data)[0];
|
||||
h2 *= m;
|
||||
};
|
||||
|
||||
h1 ^= h2 >> 18; h1 *= m;
|
||||
h2 ^= h1 >> 22; h2 *= m;
|
||||
h1 ^= h2 >> 17; h1 *= m;
|
||||
h2 ^= h1 >> 19; h2 *= m;
|
||||
|
||||
uint64 h = h1;
|
||||
|
||||
h = (h << 32) | h2;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Variant Pearson Hash general purpose hashing algorithm described
|
||||
// by Cargill in C++ Report 1994. Generates a 16-bit result.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "tier0/basetypes.h"
|
||||
#include "tier0/platform.h"
|
||||
#include "generichash.h"
|
||||
#include <ctype.h>
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Table of randomly shuffled values from 0-255 generated by:
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
void MakeRandomValues()
|
||||
{
|
||||
int i, j, r;
|
||||
unsigned t;
|
||||
srand( 0xdeadbeef );
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
g_nRandomValues[i] = (unsigned )i;
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
r = rand() & 0xff;
|
||||
t = g_nRandomValues[i];
|
||||
g_nRandomValues[i] = g_nRandomValues[r];
|
||||
g_nRandomValues[r] = t;
|
||||
}
|
||||
}
|
||||
|
||||
printf("static unsigned g_nRandomValues[256] =\n{\n");
|
||||
|
||||
for (i = 0; i < 256; i += 16)
|
||||
{
|
||||
printf("\t");
|
||||
for (j = 0; j < 16; j++)
|
||||
printf(" %3d,", g_nRandomValues[i+j]);
|
||||
printf("\n");
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
*/
|
||||
|
||||
static unsigned g_nRandomValues[256] =
|
||||
{
|
||||
238, 164, 191, 168, 115, 16, 142, 11, 213, 214, 57, 151, 248, 252, 26, 198,
|
||||
13, 105, 102, 25, 43, 42, 227, 107, 210, 251, 86, 66, 83, 193, 126, 108,
|
||||
131, 3, 64, 186, 192, 81, 37, 158, 39, 244, 14, 254, 75, 30, 2, 88,
|
||||
172, 176, 255, 69, 0, 45, 116, 139, 23, 65, 183, 148, 33, 46, 203, 20,
|
||||
143, 205, 60, 197, 118, 9, 171, 51, 233, 135, 220, 49, 71, 184, 82, 109,
|
||||
36, 161, 169, 150, 63, 96, 173, 125, 113, 67, 224, 78, 232, 215, 35, 219,
|
||||
79, 181, 41, 229, 149, 153, 111, 217, 21, 72, 120, 163, 133, 40, 122, 140,
|
||||
208, 231, 211, 200, 160, 182, 104, 110, 178, 237, 15, 101, 27, 50, 24, 189,
|
||||
177, 130, 187, 92, 253, 136, 100, 212, 19, 174, 70, 22, 170, 206, 162, 74,
|
||||
247, 5, 47, 32, 179, 117, 132, 195, 124, 123, 245, 128, 236, 223, 12, 84,
|
||||
54, 218, 146, 228, 157, 94, 106, 31, 17, 29, 194, 34, 56, 134, 239, 246,
|
||||
241, 216, 127, 98, 7, 204, 154, 152, 209, 188, 48, 61, 87, 97, 225, 85,
|
||||
90, 167, 155, 112, 145, 114, 141, 93, 250, 4, 201, 156, 38, 89, 226, 196,
|
||||
1, 235, 44, 180, 159, 121, 119, 166, 190, 144, 10, 91, 76, 230, 221, 80,
|
||||
207, 55, 58, 53, 175, 8, 6, 52, 68, 242, 18, 222, 103, 249, 147, 129,
|
||||
138, 243, 28, 185, 62, 59, 240, 202, 234, 99, 77, 73, 199, 137, 95, 165,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// String
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashString( const char *pszKey )
|
||||
{
|
||||
const uint8 *k = (const uint8 *)pszKey;
|
||||
unsigned even = 0,
|
||||
odd = 0,
|
||||
n;
|
||||
|
||||
while ((n = *k++) != 0)
|
||||
{
|
||||
even = g_nRandomValues[odd ^ n];
|
||||
if ((n = *k++) != 0)
|
||||
odd = g_nRandomValues[even ^ n];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (even << 8) | odd ;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Case-insensitive string
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashStringCaseless( const char *pszKey )
|
||||
{
|
||||
const uint8 *k = (const uint8 *) pszKey;
|
||||
unsigned even = 0,
|
||||
odd = 0,
|
||||
n;
|
||||
|
||||
while ((n = toupper(*k++)) != 0)
|
||||
{
|
||||
even = g_nRandomValues[odd ^ n];
|
||||
if ((n = toupper(*k++)) != 0)
|
||||
odd = g_nRandomValues[even ^ n];
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 32 bit conventional case-insensitive string
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashStringCaselessConventional( const char *pszKey )
|
||||
{
|
||||
unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add
|
||||
|
||||
for( ; *pszKey ; pszKey++ )
|
||||
{
|
||||
hash = ( ( hash << 5 ) + hash ) + (uint8)tolower(*pszKey);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// int hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashInt( const int n )
|
||||
{
|
||||
register unsigned even, odd;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 4-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash4( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 8-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash8( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+1);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 12-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash12( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+1);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+2);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 16-byte hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL Hash16( const void *pKey )
|
||||
{
|
||||
register const uint32 * p = (const uint32 *) pKey;
|
||||
register unsigned even,
|
||||
odd,
|
||||
n;
|
||||
n = *p;
|
||||
even = g_nRandomValues[n & 0xff];
|
||||
odd = g_nRandomValues[((n >> 8) & 0xff)];
|
||||
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ (n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+1);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+2);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
n = *(p+3);
|
||||
even = g_nRandomValues[odd ^ (n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((n >> 16) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((n >> 8) & 0xff)];
|
||||
odd = g_nRandomValues[even ^ (n & 0xff)];
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Arbitrary fixed length hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashBlock( const void *pKey, unsigned size )
|
||||
{
|
||||
const uint8 * k = (const uint8 *) pKey;
|
||||
unsigned even = 0,
|
||||
odd = 0,
|
||||
n;
|
||||
|
||||
while (size)
|
||||
{
|
||||
--size;
|
||||
n = *k++;
|
||||
even = g_nRandomValues[odd ^ n];
|
||||
if (size)
|
||||
{
|
||||
--size;
|
||||
n = *k++;
|
||||
odd = g_nRandomValues[even ^ n];
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (even << 8) | odd;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Murmur hash
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 MurmurHash2( const void * key, int len, uint32 seed )
|
||||
{
|
||||
// 'm' and 'r' are mixing constants generated offline.
|
||||
// They're not really 'magic', they just happen to work well.
|
||||
|
||||
const uint32 m = 0x5bd1e995;
|
||||
const int r = 24;
|
||||
|
||||
// Initialize the hash to a 'random' value
|
||||
|
||||
uint32 h = seed ^ len;
|
||||
|
||||
// Mix 4 bytes at a time into the hash
|
||||
|
||||
const unsigned char * data = (const unsigned char *)key;
|
||||
|
||||
while(len >= 4)
|
||||
{
|
||||
uint32 k = LittleDWord( *(uint32 *)data );
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h *= m;
|
||||
h ^= k;
|
||||
|
||||
data += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
// Handle the last few bytes of the input array
|
||||
|
||||
switch(len)
|
||||
{
|
||||
case 3: h ^= data[2] << 16;
|
||||
case 2: h ^= data[1] << 8;
|
||||
case 1: h ^= data[0];
|
||||
h *= m;
|
||||
};
|
||||
|
||||
// Do a few final mixes of the hash to ensure the last few
|
||||
// bytes are well-incorporated.
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
#define TOLOWERU( c ) ( ( uint32 ) ( ( ( c >= 'A' ) && ( c <= 'Z' ) )? c + 32 : c ) )
|
||||
uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed )
|
||||
{
|
||||
int nLen = strlen( pString );
|
||||
char *p = ( char * ) stackalloc( nLen + 1 );
|
||||
for( int i = 0; i < nLen ; i++ )
|
||||
{
|
||||
p[i] = TOLOWERU( pString[i] );
|
||||
}
|
||||
return MurmurHash2( p, nLen, nSeed );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Murmur hash, 64 bit- endian neutral
|
||||
//-----------------------------------------------------------------------------
|
||||
uint64 MurmurHash64( const void * key, int len, uint32 seed )
|
||||
{
|
||||
// 'm' and 'r' are mixing constants generated offline.
|
||||
// They're not really 'magic', they just happen to work well.
|
||||
|
||||
const uint32 m = 0x5bd1e995;
|
||||
const int r = 24;
|
||||
|
||||
// Initialize the hash to a 'random' value
|
||||
|
||||
uint32 h1 = seed ^ len;
|
||||
uint32 h2 = 0;
|
||||
|
||||
// Mix 4 bytes at a time into the hash
|
||||
|
||||
const uint32 * data = (const uint32 *)key;
|
||||
while ( len >= 8 )
|
||||
{
|
||||
uint32 k1 = LittleDWord( *data++ );
|
||||
k1 *= m; k1 ^= k1 >> r; k1 *= m;
|
||||
h1 *= m; h1 ^= k1;
|
||||
len -= 4;
|
||||
|
||||
uint32 k2 = LittleDWord( *data++ );
|
||||
k2 *= m; k2 ^= k2 >> r; k2 *= m;
|
||||
h2 *= m; h2 ^= k2;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if(len >= 4)
|
||||
{
|
||||
uint32 k1 = LittleDWord( *data++ );
|
||||
k1 *= m; k1 ^= k1 >> r; k1 *= m;
|
||||
h1 *= m; h1 ^= k1;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
// Handle the last few bytes of the input array
|
||||
switch(len)
|
||||
{
|
||||
case 3: h2 ^= ((uint8*)data)[2] << 16;
|
||||
case 2: h2 ^= ((uint8*)data)[1] << 8;
|
||||
case 1: h2 ^= ((uint8*)data)[0];
|
||||
h2 *= m;
|
||||
};
|
||||
|
||||
h1 ^= h2 >> 18; h1 *= m;
|
||||
h2 ^= h1 >> 22; h2 *= m;
|
||||
h1 ^= h2 >> 17; h1 *= m;
|
||||
h2 ^= h1 >> 19; h2 *= m;
|
||||
|
||||
uint64 h = h1;
|
||||
|
||||
h = (h << 32) | h2;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,259 +1,259 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#if defined( WIN32 ) && !defined( _X360 )
|
||||
#include <windows.h>
|
||||
#elif defined( POSIX )
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
#include "tier1/ilocalize.h"
|
||||
#include "utlstring.h"
|
||||
|
||||
#pragma warning( disable: 4018 ) // '<' : signed/unsigned mismatch
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: converts an english string to unicode
|
||||
//-----------------------------------------------------------------------------
|
||||
int ILocalize::ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSizeInBytes)
|
||||
{
|
||||
#ifdef POSIX
|
||||
return Q_UTF8ToUnicode(ansi, unicode, unicodeBufferSizeInBytes);
|
||||
#else
|
||||
int chars = MultiByteToWideChar(CP_UTF8, 0, ansi, -1, unicode, unicodeBufferSizeInBytes / sizeof(wchar_t));
|
||||
unicode[(unicodeBufferSizeInBytes / sizeof(wchar_t)) - 1] = 0;
|
||||
return chars;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: converts an unicode string to an english string
|
||||
//-----------------------------------------------------------------------------
|
||||
int ILocalize::ConvertUnicodeToANSI(const wchar_t *unicode, char *ansi, int ansiBufferSize)
|
||||
{
|
||||
#ifdef POSIX
|
||||
return Q_UnicodeToUTF8(unicode, ansi, ansiBufferSize);
|
||||
#else
|
||||
int result = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, ansi, ansiBufferSize, NULL, NULL);
|
||||
ansi[ansiBufferSize - 1] = 0;
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: construct string helper
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename T >
|
||||
void ConstructStringVArgsInternal_Impl(T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, va_list argList)
|
||||
{
|
||||
static const int k_cMaxFormatStringArguments = 9; // We only look one character ahead and start at %s1
|
||||
Assert( numFormatParameters <= k_cMaxFormatStringArguments );
|
||||
|
||||
// Safety check
|
||||
if ( unicodeOutput == NULL || unicodeBufferSizeInBytes < 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !formatString || numFormatParameters > k_cMaxFormatStringArguments )
|
||||
{
|
||||
unicodeOutput[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T);
|
||||
const T *searchPos = formatString;
|
||||
T *outputPos = unicodeOutput;
|
||||
|
||||
T *argParams[k_cMaxFormatStringArguments];
|
||||
for ( int i = 0; i < numFormatParameters; i++ )
|
||||
{
|
||||
argParams[i] = va_arg( argList, T* );
|
||||
}
|
||||
|
||||
//assumes we can't have %s10
|
||||
//assume both are 0 terminated?
|
||||
int formatLength = StringFuncs<T>::Length( formatString );
|
||||
|
||||
while ( searchPos[0] != '\0' && unicodeBufferSize > 1 )
|
||||
{
|
||||
if ( formatLength >= 3 && searchPos[0] == '%' && searchPos[1] == 's' )
|
||||
{
|
||||
//this is an escape sequence - %s1, %s2 etc, up to %s9
|
||||
|
||||
int argindex = ( searchPos[2] ) - '0' - 1; // 0 for %s1, 1 for %s2, etc.
|
||||
|
||||
if ( argindex < 0 || argindex > k_cMaxFormatStringArguments )
|
||||
{
|
||||
Warning( "Bad format string in CLocalizeStringTable::ConstructString\n" );
|
||||
*outputPos = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if ( argindex < numFormatParameters )
|
||||
{
|
||||
T const *param = argParams[argindex];
|
||||
|
||||
if ( param == NULL )
|
||||
param = StringFuncs<T>::NullDebugString();
|
||||
|
||||
int paramSize = StringFuncs<T>::Length(param);
|
||||
if (paramSize >= unicodeBufferSize)
|
||||
{
|
||||
paramSize = unicodeBufferSize - 1;
|
||||
}
|
||||
|
||||
memcpy(outputPos, param, paramSize * sizeof(T));
|
||||
|
||||
unicodeBufferSize -= paramSize;
|
||||
outputPos += paramSize;
|
||||
|
||||
searchPos += 3;
|
||||
formatLength -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertMsg( argindex < numFormatParameters, "ConstructStringVArgsInternal_Impl() - Found a %s# escape sequence whose index was more than the number of args." );
|
||||
|
||||
//copy it over, char by char
|
||||
*outputPos = *searchPos;
|
||||
|
||||
outputPos++;
|
||||
unicodeBufferSize--;
|
||||
|
||||
searchPos++;
|
||||
formatLength--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//copy it over, char by char
|
||||
*outputPos = *searchPos;
|
||||
|
||||
outputPos++;
|
||||
unicodeBufferSize--;
|
||||
|
||||
searchPos++;
|
||||
formatLength--;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure null termination
|
||||
Assert( outputPos - unicodeOutput < unicodeBufferSizeInBytes/sizeof(T) );
|
||||
*outputPos = L'\0';
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringVArgsInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, int numFormatParameters, va_list argList)
|
||||
{
|
||||
ConstructStringVArgsInternal_Impl<char>( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringVArgsInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, int numFormatParameters, va_list argList)
|
||||
{
|
||||
ConstructStringVArgsInternal_Impl<wchar_t>( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: construct string helper
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename T >
|
||||
const T *GetTypedKeyValuesString( KeyValues *pKeyValues, const char *pKeyName );
|
||||
|
||||
template < >
|
||||
const char *GetTypedKeyValuesString<char>( KeyValues *pKeyValues, const char *pKeyName )
|
||||
{
|
||||
return pKeyValues->GetString( pKeyName, "[unknown]" );
|
||||
}
|
||||
|
||||
template < >
|
||||
const wchar_t *GetTypedKeyValuesString<wchar_t>( KeyValues *pKeyValues, const char *pKeyName )
|
||||
{
|
||||
return pKeyValues->GetWString( pKeyName, L"[unknown]" );
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
void ConstructStringKeyValuesInternal_Impl( T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, KeyValues *localizationVariables )
|
||||
{
|
||||
T *outputPos = unicodeOutput;
|
||||
|
||||
//assumes we can't have %s10
|
||||
//assume both are 0 terminated?
|
||||
int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T);
|
||||
|
||||
while ( *formatString != '\0' && unicodeBufferSize > 1 )
|
||||
{
|
||||
bool shouldAdvance = true;
|
||||
|
||||
if ( *formatString == '%' )
|
||||
{
|
||||
// this is an escape sequence that specifies a variable name
|
||||
if ( formatString[1] == 's' && formatString[2] >= '0' && formatString[2] <= '9' )
|
||||
{
|
||||
// old style escape sequence, ignore
|
||||
}
|
||||
else if ( formatString[1] == '%' )
|
||||
{
|
||||
// just a '%' char, just write the second one
|
||||
formatString++;
|
||||
}
|
||||
else if ( localizationVariables )
|
||||
{
|
||||
// get out the variable name
|
||||
const T *varStart = formatString + 1;
|
||||
const T *varEnd = StringFuncs<T>::FindChar( varStart, '%' );
|
||||
|
||||
if ( varEnd && *varEnd == '%' )
|
||||
{
|
||||
shouldAdvance = false;
|
||||
|
||||
// assume variable names must be ascii, do a quick convert
|
||||
char variableName[32];
|
||||
char *vset = variableName;
|
||||
for ( const T *pws = varStart; pws < varEnd && (vset < variableName + sizeof(variableName) - 1); ++pws, ++vset )
|
||||
{
|
||||
*vset = (char)*pws;
|
||||
}
|
||||
*vset = 0;
|
||||
|
||||
// look up the variable name
|
||||
const T *value = GetTypedKeyValuesString<T>( localizationVariables, variableName );
|
||||
|
||||
int paramSize = StringFuncs<T>::Length( value );
|
||||
if (paramSize >= unicodeBufferSize)
|
||||
{
|
||||
paramSize = MAX( 0, unicodeBufferSize - 1 );
|
||||
}
|
||||
|
||||
StringFuncs<T>::Copy( outputPos, value, paramSize );
|
||||
|
||||
unicodeBufferSize -= paramSize;
|
||||
outputPos += paramSize;
|
||||
formatString = varEnd + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldAdvance)
|
||||
{
|
||||
//copy it over, char by char
|
||||
*outputPos = *formatString;
|
||||
|
||||
outputPos++;
|
||||
unicodeBufferSize--;
|
||||
|
||||
formatString++;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure null termination
|
||||
*outputPos = '\0';
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringKeyValuesInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, KeyValues *localizationVariables)
|
||||
{
|
||||
ConstructStringKeyValuesInternal_Impl<char>( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables );
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringKeyValuesInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, KeyValues *localizationVariables)
|
||||
{
|
||||
ConstructStringKeyValuesInternal_Impl<wchar_t>( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables );
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
|
||||
#if defined( WIN32 ) && !defined( _X360 )
|
||||
#include <windows.h>
|
||||
#elif defined( POSIX )
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
#include "tier1/ilocalize.h"
|
||||
#include "utlstring.h"
|
||||
|
||||
#pragma warning( disable: 4018 ) // '<' : signed/unsigned mismatch
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: converts an english string to unicode
|
||||
//-----------------------------------------------------------------------------
|
||||
int ILocalize::ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSizeInBytes)
|
||||
{
|
||||
#ifdef POSIX
|
||||
return Q_UTF8ToUnicode(ansi, unicode, unicodeBufferSizeInBytes);
|
||||
#else
|
||||
int chars = MultiByteToWideChar(CP_UTF8, 0, ansi, -1, unicode, unicodeBufferSizeInBytes / sizeof(wchar_t));
|
||||
unicode[(unicodeBufferSizeInBytes / sizeof(wchar_t)) - 1] = 0;
|
||||
return chars;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: converts an unicode string to an english string
|
||||
//-----------------------------------------------------------------------------
|
||||
int ILocalize::ConvertUnicodeToANSI(const wchar_t *unicode, char *ansi, int ansiBufferSize)
|
||||
{
|
||||
#ifdef POSIX
|
||||
return Q_UnicodeToUTF8(unicode, ansi, ansiBufferSize);
|
||||
#else
|
||||
int result = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, ansi, ansiBufferSize, NULL, NULL);
|
||||
ansi[ansiBufferSize - 1] = 0;
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: construct string helper
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename T >
|
||||
void ConstructStringVArgsInternal_Impl(T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, va_list argList)
|
||||
{
|
||||
static const int k_cMaxFormatStringArguments = 9; // We only look one character ahead and start at %s1
|
||||
Assert( numFormatParameters <= k_cMaxFormatStringArguments );
|
||||
|
||||
// Safety check
|
||||
if ( unicodeOutput == NULL || unicodeBufferSizeInBytes < 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !formatString || numFormatParameters > k_cMaxFormatStringArguments )
|
||||
{
|
||||
unicodeOutput[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T);
|
||||
const T *searchPos = formatString;
|
||||
T *outputPos = unicodeOutput;
|
||||
|
||||
T *argParams[k_cMaxFormatStringArguments];
|
||||
for ( int i = 0; i < numFormatParameters; i++ )
|
||||
{
|
||||
argParams[i] = va_arg( argList, T* );
|
||||
}
|
||||
|
||||
//assumes we can't have %s10
|
||||
//assume both are 0 terminated?
|
||||
int formatLength = StringFuncs<T>::Length( formatString );
|
||||
|
||||
while ( searchPos[0] != '\0' && unicodeBufferSize > 1 )
|
||||
{
|
||||
if ( formatLength >= 3 && searchPos[0] == '%' && searchPos[1] == 's' )
|
||||
{
|
||||
//this is an escape sequence - %s1, %s2 etc, up to %s9
|
||||
|
||||
int argindex = ( searchPos[2] ) - '0' - 1; // 0 for %s1, 1 for %s2, etc.
|
||||
|
||||
if ( argindex < 0 || argindex > k_cMaxFormatStringArguments )
|
||||
{
|
||||
Warning( "Bad format string in CLocalizeStringTable::ConstructString\n" );
|
||||
*outputPos = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if ( argindex < numFormatParameters )
|
||||
{
|
||||
T const *param = argParams[argindex];
|
||||
|
||||
if ( param == NULL )
|
||||
param = StringFuncs<T>::NullDebugString();
|
||||
|
||||
int paramSize = StringFuncs<T>::Length(param);
|
||||
if (paramSize >= unicodeBufferSize)
|
||||
{
|
||||
paramSize = unicodeBufferSize - 1;
|
||||
}
|
||||
|
||||
memcpy(outputPos, param, paramSize * sizeof(T));
|
||||
|
||||
unicodeBufferSize -= paramSize;
|
||||
outputPos += paramSize;
|
||||
|
||||
searchPos += 3;
|
||||
formatLength -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
AssertMsg( argindex < numFormatParameters, "ConstructStringVArgsInternal_Impl() - Found a %s# escape sequence whose index was more than the number of args." );
|
||||
|
||||
//copy it over, char by char
|
||||
*outputPos = *searchPos;
|
||||
|
||||
outputPos++;
|
||||
unicodeBufferSize--;
|
||||
|
||||
searchPos++;
|
||||
formatLength--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//copy it over, char by char
|
||||
*outputPos = *searchPos;
|
||||
|
||||
outputPos++;
|
||||
unicodeBufferSize--;
|
||||
|
||||
searchPos++;
|
||||
formatLength--;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure null termination
|
||||
Assert( outputPos - unicodeOutput < unicodeBufferSizeInBytes/sizeof(T) );
|
||||
*outputPos = L'\0';
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringVArgsInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, int numFormatParameters, va_list argList)
|
||||
{
|
||||
ConstructStringVArgsInternal_Impl<char>( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringVArgsInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, int numFormatParameters, va_list argList)
|
||||
{
|
||||
ConstructStringVArgsInternal_Impl<wchar_t>( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: construct string helper
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename T >
|
||||
const T *GetTypedKeyValuesString( KeyValues *pKeyValues, const char *pKeyName );
|
||||
|
||||
template < >
|
||||
const char *GetTypedKeyValuesString<char>( KeyValues *pKeyValues, const char *pKeyName )
|
||||
{
|
||||
return pKeyValues->GetString( pKeyName, "[unknown]" );
|
||||
}
|
||||
|
||||
template < >
|
||||
const wchar_t *GetTypedKeyValuesString<wchar_t>( KeyValues *pKeyValues, const char *pKeyName )
|
||||
{
|
||||
return pKeyValues->GetWString( pKeyName, L"[unknown]" );
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
void ConstructStringKeyValuesInternal_Impl( T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, KeyValues *localizationVariables )
|
||||
{
|
||||
T *outputPos = unicodeOutput;
|
||||
|
||||
//assumes we can't have %s10
|
||||
//assume both are 0 terminated?
|
||||
int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T);
|
||||
|
||||
while ( *formatString != '\0' && unicodeBufferSize > 1 )
|
||||
{
|
||||
bool shouldAdvance = true;
|
||||
|
||||
if ( *formatString == '%' )
|
||||
{
|
||||
// this is an escape sequence that specifies a variable name
|
||||
if ( formatString[1] == 's' && formatString[2] >= '0' && formatString[2] <= '9' )
|
||||
{
|
||||
// old style escape sequence, ignore
|
||||
}
|
||||
else if ( formatString[1] == '%' )
|
||||
{
|
||||
// just a '%' char, just write the second one
|
||||
formatString++;
|
||||
}
|
||||
else if ( localizationVariables )
|
||||
{
|
||||
// get out the variable name
|
||||
const T *varStart = formatString + 1;
|
||||
const T *varEnd = StringFuncs<T>::FindChar( varStart, '%' );
|
||||
|
||||
if ( varEnd && *varEnd == '%' )
|
||||
{
|
||||
shouldAdvance = false;
|
||||
|
||||
// assume variable names must be ascii, do a quick convert
|
||||
char variableName[32];
|
||||
char *vset = variableName;
|
||||
for ( const T *pws = varStart; pws < varEnd && (vset < variableName + sizeof(variableName) - 1); ++pws, ++vset )
|
||||
{
|
||||
*vset = (char)*pws;
|
||||
}
|
||||
*vset = 0;
|
||||
|
||||
// look up the variable name
|
||||
const T *value = GetTypedKeyValuesString<T>( localizationVariables, variableName );
|
||||
|
||||
int paramSize = StringFuncs<T>::Length( value );
|
||||
if (paramSize >= unicodeBufferSize)
|
||||
{
|
||||
paramSize = MAX( 0, unicodeBufferSize - 1 );
|
||||
}
|
||||
|
||||
StringFuncs<T>::Copy( outputPos, value, paramSize );
|
||||
|
||||
unicodeBufferSize -= paramSize;
|
||||
outputPos += paramSize;
|
||||
formatString = varEnd + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldAdvance)
|
||||
{
|
||||
//copy it over, char by char
|
||||
*outputPos = *formatString;
|
||||
|
||||
outputPos++;
|
||||
unicodeBufferSize--;
|
||||
|
||||
formatString++;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure null termination
|
||||
*outputPos = '\0';
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringKeyValuesInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, KeyValues *localizationVariables)
|
||||
{
|
||||
ConstructStringKeyValuesInternal_Impl<char>( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables );
|
||||
}
|
||||
|
||||
void ILocalize::ConstructStringKeyValuesInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, KeyValues *localizationVariables)
|
||||
{
|
||||
ConstructStringKeyValuesInternal_Impl<wchar_t>( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables );
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,274 +1,274 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Contains a branch-neutral binary packer for KeyValues trees.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <KeyValues.h>
|
||||
#include "kvpacker.h"
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "utlbuffer.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
#define KEYVALUES_TOKEN_SIZE 1024
|
||||
|
||||
// writes KeyValue as binary data to buffer
|
||||
bool KVPacker::WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer )
|
||||
{
|
||||
if ( buffer.IsText() ) // must be a binary buffer
|
||||
return false;
|
||||
|
||||
if ( !buffer.IsValid() ) // must be valid, no overflows etc
|
||||
return false;
|
||||
|
||||
// Write subkeys:
|
||||
|
||||
// loop through all our peers
|
||||
for ( KeyValues *dat = pNode; dat != NULL; dat = dat->GetNextKey() )
|
||||
{
|
||||
// write type
|
||||
switch ( dat->GetDataType() )
|
||||
{
|
||||
case KeyValues::TYPE_NONE:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_NONE );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_STRING:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_STRING );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_WSTRING:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_WSTRING );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_INT:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_INT );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_UINT64:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_UINT64 );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_FLOAT:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_FLOAT );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_COLOR:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_COLOR );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_PTR:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_PTR );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// write name
|
||||
buffer.PutString( dat->GetName() );
|
||||
|
||||
// write value
|
||||
switch ( dat->GetDataType() )
|
||||
{
|
||||
case KeyValues::TYPE_NONE:
|
||||
{
|
||||
if( !WriteAsBinary( dat->GetFirstSubKey(), buffer ) )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_STRING:
|
||||
{
|
||||
if (dat->GetString() && *(dat->GetString()))
|
||||
{
|
||||
buffer.PutString( dat->GetString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.PutString( "" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_WSTRING:
|
||||
{
|
||||
int nLength = dat->GetWString() ? Q_wcslen( dat->GetWString() ) : 0;
|
||||
buffer.PutShort( nLength );
|
||||
for( int k = 0; k < nLength; ++ k )
|
||||
{
|
||||
buffer.PutShort( ( unsigned short ) dat->GetWString()[k] );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_INT:
|
||||
{
|
||||
buffer.PutInt( dat->GetInt() );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_UINT64:
|
||||
{
|
||||
buffer.PutInt64( dat->GetUint64() );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_FLOAT:
|
||||
{
|
||||
buffer.PutFloat( dat->GetFloat() );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_COLOR:
|
||||
{
|
||||
Color color = dat->GetColor();
|
||||
buffer.PutUnsignedChar( color[0] );
|
||||
buffer.PutUnsignedChar( color[1] );
|
||||
buffer.PutUnsignedChar( color[2] );
|
||||
buffer.PutUnsignedChar( color[3] );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_PTR:
|
||||
{
|
||||
buffer.PutUnsignedInt( (int)dat->GetPtr() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write tail, marks end of peers
|
||||
buffer.PutUnsignedChar( PACKTYPE_NULLMARKER );
|
||||
|
||||
return buffer.IsValid();
|
||||
}
|
||||
|
||||
// read KeyValues from binary buffer, returns true if parsing was successful
|
||||
bool KVPacker::ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer )
|
||||
{
|
||||
if ( buffer.IsText() ) // must be a binary buffer
|
||||
return false;
|
||||
|
||||
if ( !buffer.IsValid() ) // must be valid, no overflows etc
|
||||
return false;
|
||||
|
||||
pNode->Clear();
|
||||
|
||||
char token[KEYVALUES_TOKEN_SIZE];
|
||||
KeyValues *dat = pNode;
|
||||
EPackType ePackType = (EPackType)buffer.GetUnsignedChar();
|
||||
|
||||
// loop through all our peers
|
||||
while ( true )
|
||||
{
|
||||
if ( ePackType == PACKTYPE_NULLMARKER )
|
||||
break; // no more peers
|
||||
|
||||
buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
|
||||
token[KEYVALUES_TOKEN_SIZE-1] = 0;
|
||||
|
||||
dat->SetName( token );
|
||||
|
||||
switch ( ePackType )
|
||||
{
|
||||
case PACKTYPE_NONE:
|
||||
{
|
||||
KeyValues *pNewNode = new KeyValues("");
|
||||
dat->AddSubKey( pNewNode );
|
||||
if( !ReadAsBinary( pNewNode, buffer ) )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_STRING:
|
||||
{
|
||||
buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
|
||||
token[KEYVALUES_TOKEN_SIZE-1] = 0;
|
||||
dat->SetStringValue( token );
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_WSTRING:
|
||||
{
|
||||
int nLength = buffer.GetShort();
|
||||
wchar_t *pTemp = (wchar_t *)stackalloc( sizeof(wchar_t) * ( 1 + nLength ) );
|
||||
|
||||
for( int k = 0; k < nLength; ++ k )
|
||||
{
|
||||
pTemp[k] = buffer.GetShort();
|
||||
}
|
||||
pTemp[ nLength ] = 0;
|
||||
|
||||
dat->SetWString( NULL, pTemp );
|
||||
break;
|
||||
}
|
||||
|
||||
case PACKTYPE_INT:
|
||||
{
|
||||
dat->SetInt( NULL, buffer.GetInt() );
|
||||
break;
|
||||
}
|
||||
|
||||
case PACKTYPE_UINT64:
|
||||
{
|
||||
dat->SetUint64( NULL, (uint64)buffer.GetInt64() );
|
||||
break;
|
||||
}
|
||||
|
||||
case PACKTYPE_FLOAT:
|
||||
{
|
||||
dat->SetFloat( NULL, buffer.GetFloat() );
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_COLOR:
|
||||
{
|
||||
Color color(
|
||||
buffer.GetUnsignedChar(),
|
||||
buffer.GetUnsignedChar(),
|
||||
buffer.GetUnsignedChar(),
|
||||
buffer.GetUnsignedChar() );
|
||||
dat->SetColor( NULL, color );
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_PTR:
|
||||
{
|
||||
dat->SetPtr( NULL, (void*)buffer.GetUnsignedInt() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !buffer.IsValid() ) // error occured
|
||||
return false;
|
||||
|
||||
ePackType = (EPackType)buffer.GetUnsignedChar();
|
||||
|
||||
if ( ePackType == PACKTYPE_NULLMARKER )
|
||||
break;
|
||||
|
||||
// new peer follows
|
||||
KeyValues *pNewPeer = new KeyValues("");
|
||||
dat->SetNextKey( pNewPeer );
|
||||
dat = pNewPeer;
|
||||
}
|
||||
|
||||
return buffer.IsValid();
|
||||
}
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Contains a branch-neutral binary packer for KeyValues trees.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <KeyValues.h>
|
||||
#include "kvpacker.h"
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "utlbuffer.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
#define KEYVALUES_TOKEN_SIZE 1024
|
||||
|
||||
// writes KeyValue as binary data to buffer
|
||||
bool KVPacker::WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer )
|
||||
{
|
||||
if ( buffer.IsText() ) // must be a binary buffer
|
||||
return false;
|
||||
|
||||
if ( !buffer.IsValid() ) // must be valid, no overflows etc
|
||||
return false;
|
||||
|
||||
// Write subkeys:
|
||||
|
||||
// loop through all our peers
|
||||
for ( KeyValues *dat = pNode; dat != NULL; dat = dat->GetNextKey() )
|
||||
{
|
||||
// write type
|
||||
switch ( dat->GetDataType() )
|
||||
{
|
||||
case KeyValues::TYPE_NONE:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_NONE );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_STRING:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_STRING );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_WSTRING:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_WSTRING );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_INT:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_INT );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_UINT64:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_UINT64 );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_FLOAT:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_FLOAT );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_COLOR:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_COLOR );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_PTR:
|
||||
{
|
||||
buffer.PutUnsignedChar( PACKTYPE_PTR );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// write name
|
||||
buffer.PutString( dat->GetName() );
|
||||
|
||||
// write value
|
||||
switch ( dat->GetDataType() )
|
||||
{
|
||||
case KeyValues::TYPE_NONE:
|
||||
{
|
||||
if( !WriteAsBinary( dat->GetFirstSubKey(), buffer ) )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_STRING:
|
||||
{
|
||||
if (dat->GetString() && *(dat->GetString()))
|
||||
{
|
||||
buffer.PutString( dat->GetString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.PutString( "" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_WSTRING:
|
||||
{
|
||||
int nLength = dat->GetWString() ? Q_wcslen( dat->GetWString() ) : 0;
|
||||
buffer.PutShort( nLength );
|
||||
for( int k = 0; k < nLength; ++ k )
|
||||
{
|
||||
buffer.PutShort( ( unsigned short ) dat->GetWString()[k] );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_INT:
|
||||
{
|
||||
buffer.PutInt( dat->GetInt() );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_UINT64:
|
||||
{
|
||||
buffer.PutInt64( dat->GetUint64() );
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyValues::TYPE_FLOAT:
|
||||
{
|
||||
buffer.PutFloat( dat->GetFloat() );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_COLOR:
|
||||
{
|
||||
Color color = dat->GetColor();
|
||||
buffer.PutUnsignedChar( color[0] );
|
||||
buffer.PutUnsignedChar( color[1] );
|
||||
buffer.PutUnsignedChar( color[2] );
|
||||
buffer.PutUnsignedChar( color[3] );
|
||||
break;
|
||||
}
|
||||
case KeyValues::TYPE_PTR:
|
||||
{
|
||||
buffer.PutUnsignedInt( (int)dat->GetPtr() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write tail, marks end of peers
|
||||
buffer.PutUnsignedChar( PACKTYPE_NULLMARKER );
|
||||
|
||||
return buffer.IsValid();
|
||||
}
|
||||
|
||||
// read KeyValues from binary buffer, returns true if parsing was successful
|
||||
bool KVPacker::ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer )
|
||||
{
|
||||
if ( buffer.IsText() ) // must be a binary buffer
|
||||
return false;
|
||||
|
||||
if ( !buffer.IsValid() ) // must be valid, no overflows etc
|
||||
return false;
|
||||
|
||||
pNode->Clear();
|
||||
|
||||
char token[KEYVALUES_TOKEN_SIZE];
|
||||
KeyValues *dat = pNode;
|
||||
EPackType ePackType = (EPackType)buffer.GetUnsignedChar();
|
||||
|
||||
// loop through all our peers
|
||||
while ( true )
|
||||
{
|
||||
if ( ePackType == PACKTYPE_NULLMARKER )
|
||||
break; // no more peers
|
||||
|
||||
buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
|
||||
token[KEYVALUES_TOKEN_SIZE-1] = 0;
|
||||
|
||||
dat->SetName( token );
|
||||
|
||||
switch ( ePackType )
|
||||
{
|
||||
case PACKTYPE_NONE:
|
||||
{
|
||||
KeyValues *pNewNode = new KeyValues("");
|
||||
dat->AddSubKey( pNewNode );
|
||||
if( !ReadAsBinary( pNewNode, buffer ) )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_STRING:
|
||||
{
|
||||
buffer.GetString( token, KEYVALUES_TOKEN_SIZE-1 );
|
||||
token[KEYVALUES_TOKEN_SIZE-1] = 0;
|
||||
dat->SetStringValue( token );
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_WSTRING:
|
||||
{
|
||||
int nLength = buffer.GetShort();
|
||||
wchar_t *pTemp = (wchar_t *)stackalloc( sizeof(wchar_t) * ( 1 + nLength ) );
|
||||
|
||||
for( int k = 0; k < nLength; ++ k )
|
||||
{
|
||||
pTemp[k] = buffer.GetShort();
|
||||
}
|
||||
pTemp[ nLength ] = 0;
|
||||
|
||||
dat->SetWString( NULL, pTemp );
|
||||
break;
|
||||
}
|
||||
|
||||
case PACKTYPE_INT:
|
||||
{
|
||||
dat->SetInt( NULL, buffer.GetInt() );
|
||||
break;
|
||||
}
|
||||
|
||||
case PACKTYPE_UINT64:
|
||||
{
|
||||
dat->SetUint64( NULL, (uint64)buffer.GetInt64() );
|
||||
break;
|
||||
}
|
||||
|
||||
case PACKTYPE_FLOAT:
|
||||
{
|
||||
dat->SetFloat( NULL, buffer.GetFloat() );
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_COLOR:
|
||||
{
|
||||
Color color(
|
||||
buffer.GetUnsignedChar(),
|
||||
buffer.GetUnsignedChar(),
|
||||
buffer.GetUnsignedChar(),
|
||||
buffer.GetUnsignedChar() );
|
||||
dat->SetColor( NULL, color );
|
||||
break;
|
||||
}
|
||||
case PACKTYPE_PTR:
|
||||
{
|
||||
dat->SetPtr( NULL, (void*)buffer.GetUnsignedInt() );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !buffer.IsValid() ) // error occured
|
||||
return false;
|
||||
|
||||
ePackType = (EPackType)buffer.GetUnsignedChar();
|
||||
|
||||
if ( ePackType == PACKTYPE_NULLMARKER )
|
||||
break;
|
||||
|
||||
// new peer follows
|
||||
KeyValues *pNewPeer = new KeyValues("");
|
||||
dat->SetNextKey( pNewPeer );
|
||||
dat = pNewPeer;
|
||||
}
|
||||
|
||||
return buffer.IsValid();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,312 +1,312 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "mempool.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include "tier0/dbg.h"
|
||||
#include <ctype.h>
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
// Should be last include
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
MemoryPoolReportFunc_t CUtlMemoryPool::g_ReportFunc = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Error reporting... (debug only)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func )
|
||||
{
|
||||
g_ReportFunc = func;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlMemoryPool::CUtlMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment )
|
||||
{
|
||||
#ifdef _X360
|
||||
if( numElements > 0 && growMode != GROW_NONE )
|
||||
{
|
||||
numElements = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_nAlignment = ( nAlignment != 0 ) ? nAlignment : 1;
|
||||
Assert( IsPowerOfTwo( m_nAlignment ) );
|
||||
m_BlockSize = blockSize < sizeof(void*) ? sizeof(void*) : blockSize;
|
||||
m_BlockSize = AlignValue( m_BlockSize, m_nAlignment );
|
||||
m_BlocksPerBlob = numElements;
|
||||
m_PeakAlloc = 0;
|
||||
m_GrowMode = growMode;
|
||||
if ( !pszAllocOwner )
|
||||
{
|
||||
pszAllocOwner = __FILE__;
|
||||
}
|
||||
m_pszAllocOwner = pszAllocOwner;
|
||||
Init();
|
||||
AddNewBlob();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees the memory contained in the mempool, and invalidates it for
|
||||
// any further use.
|
||||
// Input : *memPool - the mempool to shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlMemoryPool::~CUtlMemoryPool()
|
||||
{
|
||||
if (m_BlocksAllocated > 0)
|
||||
{
|
||||
ReportLeaks();
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Resets the pool
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Init()
|
||||
{
|
||||
m_NumBlobs = 0;
|
||||
m_BlocksAllocated = 0;
|
||||
m_pHeadOfFreeList = 0;
|
||||
m_BlobHead.m_pNext = m_BlobHead.m_pPrev = &m_BlobHead;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Frees everything
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Clear()
|
||||
{
|
||||
// Free everything..
|
||||
CBlob *pNext;
|
||||
for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pNext )
|
||||
{
|
||||
pNext = pCur->m_pNext;
|
||||
free( pCur );
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reports memory leaks
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlMemoryPool::ReportLeaks()
|
||||
{
|
||||
if (!g_ReportFunc)
|
||||
return;
|
||||
|
||||
g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// walk and destroy the free list so it doesn't intefere in the scan
|
||||
while (m_pHeadOfFreeList != NULL)
|
||||
{
|
||||
void *next = *((void**)m_pHeadOfFreeList);
|
||||
memset(m_pHeadOfFreeList, 0, m_BlockSize);
|
||||
m_pHeadOfFreeList = next;
|
||||
}
|
||||
|
||||
g_ReportFunc("Dumping memory: \'");
|
||||
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
// scan the memory block and dump the leaks
|
||||
char *scanPoint = (char *)pCur->m_Data;
|
||||
char *scanEnd = pCur->m_Data + pCur->m_NumBytes;
|
||||
bool needSpace = false;
|
||||
|
||||
while (scanPoint < scanEnd)
|
||||
{
|
||||
// search for and dump any strings
|
||||
if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint))
|
||||
{
|
||||
g_ReportFunc("%c", *scanPoint);
|
||||
needSpace = true;
|
||||
}
|
||||
else if (needSpace)
|
||||
{
|
||||
needSpace = false;
|
||||
g_ReportFunc(" ");
|
||||
}
|
||||
|
||||
scanPoint++;
|
||||
}
|
||||
}
|
||||
|
||||
g_ReportFunc("\'\n");
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::AddNewBlob()
|
||||
{
|
||||
MEM_ALLOC_CREDIT_(m_pszAllocOwner);
|
||||
|
||||
int sizeMultiplier;
|
||||
|
||||
if( m_GrowMode == GROW_SLOW )
|
||||
{
|
||||
sizeMultiplier = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_GrowMode == GROW_NONE )
|
||||
{
|
||||
// Can only have one allocation when we're in this mode
|
||||
if( m_NumBlobs != 0 )
|
||||
{
|
||||
Assert( !"CUtlMemoryPool::AddNewBlob: mode == GROW_NONE" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// GROW_FAST and GROW_NONE use this.
|
||||
sizeMultiplier = m_NumBlobs + 1;
|
||||
}
|
||||
|
||||
// maybe use something other than malloc?
|
||||
int nElements = m_BlocksPerBlob * sizeMultiplier;
|
||||
int blobSize = m_BlockSize * nElements;
|
||||
CBlob *pBlob = (CBlob*)malloc( sizeof(CBlob) - 1 + blobSize + ( m_nAlignment - 1 ) );
|
||||
Assert( pBlob );
|
||||
|
||||
// Link it in at the end of the blob list.
|
||||
pBlob->m_NumBytes = blobSize;
|
||||
pBlob->m_pNext = &m_BlobHead;
|
||||
pBlob->m_pPrev = pBlob->m_pNext->m_pPrev;
|
||||
pBlob->m_pNext->m_pPrev = pBlob->m_pPrev->m_pNext = pBlob;
|
||||
|
||||
// setup the free list
|
||||
m_pHeadOfFreeList = AlignValue( pBlob->m_Data, m_nAlignment );
|
||||
Assert (m_pHeadOfFreeList);
|
||||
|
||||
void **newBlob = (void**)m_pHeadOfFreeList;
|
||||
for (int j = 0; j < nElements-1; j++)
|
||||
{
|
||||
newBlob[0] = (char*)newBlob + m_BlockSize;
|
||||
newBlob = (void**)newBlob[0];
|
||||
}
|
||||
|
||||
// null terminate list
|
||||
newBlob[0] = NULL;
|
||||
m_NumBlobs++;
|
||||
}
|
||||
|
||||
|
||||
void* CUtlMemoryPool::Alloc()
|
||||
{
|
||||
return Alloc( m_BlockSize );
|
||||
}
|
||||
|
||||
|
||||
void* CUtlMemoryPool::AllocZero()
|
||||
{
|
||||
return AllocZero( m_BlockSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocs a single block of memory from the pool.
|
||||
// Input : amount -
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CUtlMemoryPool::Alloc( size_t amount )
|
||||
{
|
||||
void *returnBlock;
|
||||
|
||||
if ( amount > (unsigned int)m_BlockSize )
|
||||
return NULL;
|
||||
|
||||
if( !m_pHeadOfFreeList )
|
||||
{
|
||||
// returning NULL is fine in GROW_NONE
|
||||
if( m_GrowMode == GROW_NONE )
|
||||
{
|
||||
//Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with GROW_NONE" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// overflow
|
||||
AddNewBlob();
|
||||
|
||||
// still failure, error out
|
||||
if( !m_pHeadOfFreeList )
|
||||
{
|
||||
Assert( !"CUtlMemoryPool::Alloc: ran out of memory" );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
m_BlocksAllocated++;
|
||||
m_PeakAlloc = max(m_PeakAlloc, m_BlocksAllocated);
|
||||
|
||||
returnBlock = m_pHeadOfFreeList;
|
||||
|
||||
// move the pointer the next block
|
||||
m_pHeadOfFreeList = *((void**)m_pHeadOfFreeList);
|
||||
|
||||
return returnBlock;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocs a single block of memory from the pool, zeroes the memory before returning
|
||||
// Input : amount -
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CUtlMemoryPool::AllocZero( size_t amount )
|
||||
{
|
||||
void *mem = Alloc( amount );
|
||||
if ( mem )
|
||||
{
|
||||
V_memset( mem, 0x00, amount );
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees a block of memory
|
||||
// Input : *memBlock - the memory to free
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Free( void *memBlock )
|
||||
{
|
||||
if ( !memBlock )
|
||||
return; // trying to delete NULL pointer, ignore
|
||||
|
||||
#ifdef _DEBUG
|
||||
// check to see if the memory is from the allocated range
|
||||
bool bOK = false;
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
if (memBlock >= pCur->m_Data && (char*)memBlock < (pCur->m_Data + pCur->m_NumBytes))
|
||||
{
|
||||
bOK = true;
|
||||
}
|
||||
}
|
||||
Assert (bOK);
|
||||
#endif // _DEBUG
|
||||
|
||||
#ifdef _DEBUG
|
||||
// invalidate the memory
|
||||
memset( memBlock, 0xDD, m_BlockSize );
|
||||
#endif
|
||||
|
||||
m_BlocksAllocated--;
|
||||
|
||||
// make the block point to the first item in the list
|
||||
*((void**)memBlock) = m_pHeadOfFreeList;
|
||||
|
||||
// the list head is now the new block
|
||||
m_pHeadOfFreeList = memBlock;
|
||||
}
|
||||
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "mempool.h"
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include "tier0/dbg.h"
|
||||
#include <ctype.h>
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
// Should be last include
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
MemoryPoolReportFunc_t CUtlMemoryPool::g_ReportFunc = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Error reporting... (debug only)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func )
|
||||
{
|
||||
g_ReportFunc = func;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlMemoryPool::CUtlMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment )
|
||||
{
|
||||
#ifdef _X360
|
||||
if( numElements > 0 && growMode != GROW_NONE )
|
||||
{
|
||||
numElements = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_nAlignment = ( nAlignment != 0 ) ? nAlignment : 1;
|
||||
Assert( IsPowerOfTwo( m_nAlignment ) );
|
||||
m_BlockSize = blockSize < sizeof(void*) ? sizeof(void*) : blockSize;
|
||||
m_BlockSize = AlignValue( m_BlockSize, m_nAlignment );
|
||||
m_BlocksPerBlob = numElements;
|
||||
m_PeakAlloc = 0;
|
||||
m_GrowMode = growMode;
|
||||
if ( !pszAllocOwner )
|
||||
{
|
||||
pszAllocOwner = __FILE__;
|
||||
}
|
||||
m_pszAllocOwner = pszAllocOwner;
|
||||
Init();
|
||||
AddNewBlob();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees the memory contained in the mempool, and invalidates it for
|
||||
// any further use.
|
||||
// Input : *memPool - the mempool to shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlMemoryPool::~CUtlMemoryPool()
|
||||
{
|
||||
if (m_BlocksAllocated > 0)
|
||||
{
|
||||
ReportLeaks();
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Resets the pool
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Init()
|
||||
{
|
||||
m_NumBlobs = 0;
|
||||
m_BlocksAllocated = 0;
|
||||
m_pHeadOfFreeList = 0;
|
||||
m_BlobHead.m_pNext = m_BlobHead.m_pPrev = &m_BlobHead;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Frees everything
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Clear()
|
||||
{
|
||||
// Free everything..
|
||||
CBlob *pNext;
|
||||
for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pNext )
|
||||
{
|
||||
pNext = pCur->m_pNext;
|
||||
free( pCur );
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reports memory leaks
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlMemoryPool::ReportLeaks()
|
||||
{
|
||||
if (!g_ReportFunc)
|
||||
return;
|
||||
|
||||
g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// walk and destroy the free list so it doesn't intefere in the scan
|
||||
while (m_pHeadOfFreeList != NULL)
|
||||
{
|
||||
void *next = *((void**)m_pHeadOfFreeList);
|
||||
memset(m_pHeadOfFreeList, 0, m_BlockSize);
|
||||
m_pHeadOfFreeList = next;
|
||||
}
|
||||
|
||||
g_ReportFunc("Dumping memory: \'");
|
||||
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
// scan the memory block and dump the leaks
|
||||
char *scanPoint = (char *)pCur->m_Data;
|
||||
char *scanEnd = pCur->m_Data + pCur->m_NumBytes;
|
||||
bool needSpace = false;
|
||||
|
||||
while (scanPoint < scanEnd)
|
||||
{
|
||||
// search for and dump any strings
|
||||
if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint))
|
||||
{
|
||||
g_ReportFunc("%c", *scanPoint);
|
||||
needSpace = true;
|
||||
}
|
||||
else if (needSpace)
|
||||
{
|
||||
needSpace = false;
|
||||
g_ReportFunc(" ");
|
||||
}
|
||||
|
||||
scanPoint++;
|
||||
}
|
||||
}
|
||||
|
||||
g_ReportFunc("\'\n");
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::AddNewBlob()
|
||||
{
|
||||
MEM_ALLOC_CREDIT_(m_pszAllocOwner);
|
||||
|
||||
int sizeMultiplier;
|
||||
|
||||
if( m_GrowMode == GROW_SLOW )
|
||||
{
|
||||
sizeMultiplier = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_GrowMode == GROW_NONE )
|
||||
{
|
||||
// Can only have one allocation when we're in this mode
|
||||
if( m_NumBlobs != 0 )
|
||||
{
|
||||
Assert( !"CUtlMemoryPool::AddNewBlob: mode == GROW_NONE" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// GROW_FAST and GROW_NONE use this.
|
||||
sizeMultiplier = m_NumBlobs + 1;
|
||||
}
|
||||
|
||||
// maybe use something other than malloc?
|
||||
int nElements = m_BlocksPerBlob * sizeMultiplier;
|
||||
int blobSize = m_BlockSize * nElements;
|
||||
CBlob *pBlob = (CBlob*)malloc( sizeof(CBlob) - 1 + blobSize + ( m_nAlignment - 1 ) );
|
||||
Assert( pBlob );
|
||||
|
||||
// Link it in at the end of the blob list.
|
||||
pBlob->m_NumBytes = blobSize;
|
||||
pBlob->m_pNext = &m_BlobHead;
|
||||
pBlob->m_pPrev = pBlob->m_pNext->m_pPrev;
|
||||
pBlob->m_pNext->m_pPrev = pBlob->m_pPrev->m_pNext = pBlob;
|
||||
|
||||
// setup the free list
|
||||
m_pHeadOfFreeList = AlignValue( pBlob->m_Data, m_nAlignment );
|
||||
Assert (m_pHeadOfFreeList);
|
||||
|
||||
void **newBlob = (void**)m_pHeadOfFreeList;
|
||||
for (int j = 0; j < nElements-1; j++)
|
||||
{
|
||||
newBlob[0] = (char*)newBlob + m_BlockSize;
|
||||
newBlob = (void**)newBlob[0];
|
||||
}
|
||||
|
||||
// null terminate list
|
||||
newBlob[0] = NULL;
|
||||
m_NumBlobs++;
|
||||
}
|
||||
|
||||
|
||||
void* CUtlMemoryPool::Alloc()
|
||||
{
|
||||
return Alloc( m_BlockSize );
|
||||
}
|
||||
|
||||
|
||||
void* CUtlMemoryPool::AllocZero()
|
||||
{
|
||||
return AllocZero( m_BlockSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocs a single block of memory from the pool.
|
||||
// Input : amount -
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CUtlMemoryPool::Alloc( size_t amount )
|
||||
{
|
||||
void *returnBlock;
|
||||
|
||||
if ( amount > (unsigned int)m_BlockSize )
|
||||
return NULL;
|
||||
|
||||
if( !m_pHeadOfFreeList )
|
||||
{
|
||||
// returning NULL is fine in GROW_NONE
|
||||
if( m_GrowMode == GROW_NONE )
|
||||
{
|
||||
//Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with GROW_NONE" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// overflow
|
||||
AddNewBlob();
|
||||
|
||||
// still failure, error out
|
||||
if( !m_pHeadOfFreeList )
|
||||
{
|
||||
Assert( !"CUtlMemoryPool::Alloc: ran out of memory" );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
m_BlocksAllocated++;
|
||||
m_PeakAlloc = max(m_PeakAlloc, m_BlocksAllocated);
|
||||
|
||||
returnBlock = m_pHeadOfFreeList;
|
||||
|
||||
// move the pointer the next block
|
||||
m_pHeadOfFreeList = *((void**)m_pHeadOfFreeList);
|
||||
|
||||
return returnBlock;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocs a single block of memory from the pool, zeroes the memory before returning
|
||||
// Input : amount -
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CUtlMemoryPool::AllocZero( size_t amount )
|
||||
{
|
||||
void *mem = Alloc( amount );
|
||||
if ( mem )
|
||||
{
|
||||
V_memset( mem, 0x00, amount );
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees a block of memory
|
||||
// Input : *memBlock - the memory to free
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Free( void *memBlock )
|
||||
{
|
||||
if ( !memBlock )
|
||||
return; // trying to delete NULL pointer, ignore
|
||||
|
||||
#ifdef _DEBUG
|
||||
// check to see if the memory is from the allocated range
|
||||
bool bOK = false;
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
if (memBlock >= pCur->m_Data && (char*)memBlock < (pCur->m_Data + pCur->m_NumBytes))
|
||||
{
|
||||
bOK = true;
|
||||
}
|
||||
}
|
||||
Assert (bOK);
|
||||
#endif // _DEBUG
|
||||
|
||||
#ifdef _DEBUG
|
||||
// invalidate the memory
|
||||
memset( memBlock, 0xDD, m_BlockSize );
|
||||
#endif
|
||||
|
||||
m_BlocksAllocated--;
|
||||
|
||||
// make the block point to the first item in the list
|
||||
*((void**)memBlock) = m_pHeadOfFreeList;
|
||||
|
||||
// the list head is now the new block
|
||||
m_pHeadOfFreeList = memBlock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,297 +1,297 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#define WIN_32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define VA_COMMIT_FLAGS MEM_COMMIT
|
||||
#define VA_RESERVE_FLAGS MEM_RESERVE
|
||||
#elif defined( _X360 )
|
||||
#define VA_COMMIT_FLAGS (MEM_COMMIT|MEM_NOZERO|MEM_LARGE_PAGES)
|
||||
#define VA_RESERVE_FLAGS (MEM_RESERVE|MEM_LARGE_PAGES)
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "memstack.h"
|
||||
#include "utlmap.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4073)
|
||||
#pragma init_seg(lib)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CMemoryStack::CMemoryStack()
|
||||
: m_pBase( NULL ),
|
||||
m_pNextAlloc( NULL ),
|
||||
m_pAllocLimit( NULL ),
|
||||
m_pCommitLimit( NULL ),
|
||||
m_alignment( 16 ),
|
||||
#if defined(_WIN32)
|
||||
m_commitSize( 0 ),
|
||||
m_minCommit( 0 ),
|
||||
#endif
|
||||
m_maxSize( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
CMemoryStack::~CMemoryStack()
|
||||
{
|
||||
if ( m_pBase )
|
||||
Term();
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::Init( unsigned maxSize, unsigned commitSize, unsigned initialCommit, unsigned alignment )
|
||||
{
|
||||
Assert( !m_pBase );
|
||||
|
||||
#ifdef _X360
|
||||
m_bPhysical = false;
|
||||
#endif
|
||||
|
||||
m_maxSize = maxSize;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
Assert( m_alignment == alignment );
|
||||
Assert( m_maxSize > 0 );
|
||||
|
||||
#if defined(_WIN32)
|
||||
if ( commitSize != 0 )
|
||||
{
|
||||
m_commitSize = commitSize;
|
||||
}
|
||||
|
||||
unsigned pageSize;
|
||||
|
||||
#ifndef _X360
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo( &sysInfo );
|
||||
Assert( !( sysInfo.dwPageSize & (sysInfo.dwPageSize-1)) );
|
||||
pageSize = sysInfo.dwPageSize;
|
||||
#else
|
||||
pageSize = 64*1024;
|
||||
#endif
|
||||
|
||||
if ( m_commitSize == 0 )
|
||||
{
|
||||
m_commitSize = pageSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_commitSize = AlignValue( m_commitSize, pageSize );
|
||||
}
|
||||
|
||||
m_maxSize = AlignValue( m_maxSize, m_commitSize );
|
||||
|
||||
Assert( m_maxSize % pageSize == 0 && m_commitSize % pageSize == 0 && m_commitSize <= m_maxSize );
|
||||
|
||||
m_pBase = (unsigned char *)VirtualAlloc( NULL, m_maxSize, VA_RESERVE_FLAGS, PAGE_NOACCESS );
|
||||
Assert( m_pBase );
|
||||
m_pCommitLimit = m_pNextAlloc = m_pBase;
|
||||
|
||||
if ( initialCommit )
|
||||
{
|
||||
initialCommit = AlignValue( initialCommit, m_commitSize );
|
||||
Assert( initialCommit < m_maxSize );
|
||||
if ( !VirtualAlloc( m_pCommitLimit, initialCommit, VA_COMMIT_FLAGS, PAGE_READWRITE ) )
|
||||
return false;
|
||||
m_minCommit = initialCommit;
|
||||
m_pCommitLimit += initialCommit;
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
}
|
||||
|
||||
#else
|
||||
m_pBase = (byte *)MemAlloc_AllocAligned( m_maxSize, alignment ? alignment : 1 );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
#endif
|
||||
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
#ifdef _X360
|
||||
bool CMemoryStack::InitPhysical( unsigned size, unsigned alignment )
|
||||
{
|
||||
m_bPhysical = true;
|
||||
|
||||
m_maxSize = m_commitSize = size;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
int flags = PAGE_READWRITE;
|
||||
if ( size >= 16*1024*1024 )
|
||||
{
|
||||
flags |= MEM_16MB_PAGES;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags |= MEM_LARGE_PAGES;
|
||||
}
|
||||
m_pBase = (unsigned char *)XPhysicalAlloc( m_maxSize, MAXULONG_PTR, 4096, flags );
|
||||
Assert( m_pBase );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Term()
|
||||
{
|
||||
FreeAll();
|
||||
if ( m_pBase )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
VirtualFree( m_pBase, 0, MEM_RELEASE );
|
||||
#else
|
||||
MemAlloc_FreeAligned( m_pBase );
|
||||
#endif
|
||||
m_pBase = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
int CMemoryStack::GetSize()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return m_pCommitLimit - m_pBase;
|
||||
#else
|
||||
return m_maxSize;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::CommitTo( byte *pNextAlloc ) RESTRICT
|
||||
{
|
||||
#ifdef _X360
|
||||
if ( m_bPhysical )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
unsigned char * pNewCommitLimit = AlignValue( pNextAlloc, m_commitSize );
|
||||
unsigned commitSize = pNewCommitLimit - m_pCommitLimit;
|
||||
|
||||
if ( GetSize() )
|
||||
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
|
||||
|
||||
if( m_pCommitLimit + commitSize > m_pAllocLimit )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !VirtualAlloc( m_pCommitLimit, commitSize, VA_COMMIT_FLAGS, PAGE_READWRITE ) )
|
||||
{
|
||||
Assert( 0 );
|
||||
return false;
|
||||
}
|
||||
m_pCommitLimit = pNewCommitLimit;
|
||||
|
||||
if ( GetSize() )
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
return true;
|
||||
#else
|
||||
Assert( 0 );
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit )
|
||||
{
|
||||
void *pAllocPoint = m_pBase + mark;
|
||||
Assert( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc );
|
||||
|
||||
if ( pAllocPoint >= m_pBase && pAllocPoint < m_pNextAlloc )
|
||||
{
|
||||
if ( bDecommit )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
unsigned char *pDecommitPoint = AlignValue( (unsigned char *)pAllocPoint, m_commitSize );
|
||||
|
||||
if ( pDecommitPoint < m_pBase + m_minCommit )
|
||||
{
|
||||
pDecommitPoint = m_pBase + m_minCommit;
|
||||
}
|
||||
|
||||
unsigned decommitSize = m_pCommitLimit - pDecommitPoint;
|
||||
|
||||
if ( decommitSize > 0 )
|
||||
{
|
||||
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
|
||||
|
||||
VirtualFree( pDecommitPoint, decommitSize, MEM_DECOMMIT );
|
||||
m_pCommitLimit = pDecommitPoint;
|
||||
|
||||
if ( mark > 0 )
|
||||
{
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
m_pNextAlloc = (unsigned char *)pAllocPoint;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeAll( bool bDecommit )
|
||||
{
|
||||
if ( m_pBase && m_pCommitLimit - m_pBase > 0 )
|
||||
{
|
||||
if ( bDecommit )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
|
||||
|
||||
VirtualFree( m_pBase, m_pCommitLimit - m_pBase, MEM_DECOMMIT );
|
||||
m_pCommitLimit = m_pBase;
|
||||
#endif
|
||||
}
|
||||
m_pNextAlloc = m_pBase;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Access( void **ppRegion, unsigned *pBytes )
|
||||
{
|
||||
*ppRegion = m_pBase;
|
||||
*pBytes = ( m_pNextAlloc - m_pBase);
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::PrintContents()
|
||||
{
|
||||
Msg( "Total used memory: %d\n", GetUsed() );
|
||||
Msg( "Total committed memory: %d\n", GetSize() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#define WIN_32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define VA_COMMIT_FLAGS MEM_COMMIT
|
||||
#define VA_RESERVE_FLAGS MEM_RESERVE
|
||||
#elif defined( _X360 )
|
||||
#define VA_COMMIT_FLAGS (MEM_COMMIT|MEM_NOZERO|MEM_LARGE_PAGES)
|
||||
#define VA_RESERVE_FLAGS (MEM_RESERVE|MEM_LARGE_PAGES)
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "memstack.h"
|
||||
#include "utlmap.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4073)
|
||||
#pragma init_seg(lib)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CMemoryStack::CMemoryStack()
|
||||
: m_pBase( NULL ),
|
||||
m_pNextAlloc( NULL ),
|
||||
m_pAllocLimit( NULL ),
|
||||
m_pCommitLimit( NULL ),
|
||||
m_alignment( 16 ),
|
||||
#if defined(_WIN32)
|
||||
m_commitSize( 0 ),
|
||||
m_minCommit( 0 ),
|
||||
#endif
|
||||
m_maxSize( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
CMemoryStack::~CMemoryStack()
|
||||
{
|
||||
if ( m_pBase )
|
||||
Term();
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::Init( unsigned maxSize, unsigned commitSize, unsigned initialCommit, unsigned alignment )
|
||||
{
|
||||
Assert( !m_pBase );
|
||||
|
||||
#ifdef _X360
|
||||
m_bPhysical = false;
|
||||
#endif
|
||||
|
||||
m_maxSize = maxSize;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
Assert( m_alignment == alignment );
|
||||
Assert( m_maxSize > 0 );
|
||||
|
||||
#if defined(_WIN32)
|
||||
if ( commitSize != 0 )
|
||||
{
|
||||
m_commitSize = commitSize;
|
||||
}
|
||||
|
||||
unsigned pageSize;
|
||||
|
||||
#ifndef _X360
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo( &sysInfo );
|
||||
Assert( !( sysInfo.dwPageSize & (sysInfo.dwPageSize-1)) );
|
||||
pageSize = sysInfo.dwPageSize;
|
||||
#else
|
||||
pageSize = 64*1024;
|
||||
#endif
|
||||
|
||||
if ( m_commitSize == 0 )
|
||||
{
|
||||
m_commitSize = pageSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_commitSize = AlignValue( m_commitSize, pageSize );
|
||||
}
|
||||
|
||||
m_maxSize = AlignValue( m_maxSize, m_commitSize );
|
||||
|
||||
Assert( m_maxSize % pageSize == 0 && m_commitSize % pageSize == 0 && m_commitSize <= m_maxSize );
|
||||
|
||||
m_pBase = (unsigned char *)VirtualAlloc( NULL, m_maxSize, VA_RESERVE_FLAGS, PAGE_NOACCESS );
|
||||
Assert( m_pBase );
|
||||
m_pCommitLimit = m_pNextAlloc = m_pBase;
|
||||
|
||||
if ( initialCommit )
|
||||
{
|
||||
initialCommit = AlignValue( initialCommit, m_commitSize );
|
||||
Assert( initialCommit < m_maxSize );
|
||||
if ( !VirtualAlloc( m_pCommitLimit, initialCommit, VA_COMMIT_FLAGS, PAGE_READWRITE ) )
|
||||
return false;
|
||||
m_minCommit = initialCommit;
|
||||
m_pCommitLimit += initialCommit;
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
}
|
||||
|
||||
#else
|
||||
m_pBase = (byte *)MemAlloc_AllocAligned( m_maxSize, alignment ? alignment : 1 );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
#endif
|
||||
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
#ifdef _X360
|
||||
bool CMemoryStack::InitPhysical( unsigned size, unsigned alignment )
|
||||
{
|
||||
m_bPhysical = true;
|
||||
|
||||
m_maxSize = m_commitSize = size;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
int flags = PAGE_READWRITE;
|
||||
if ( size >= 16*1024*1024 )
|
||||
{
|
||||
flags |= MEM_16MB_PAGES;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags |= MEM_LARGE_PAGES;
|
||||
}
|
||||
m_pBase = (unsigned char *)XPhysicalAlloc( m_maxSize, MAXULONG_PTR, 4096, flags );
|
||||
Assert( m_pBase );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Term()
|
||||
{
|
||||
FreeAll();
|
||||
if ( m_pBase )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
VirtualFree( m_pBase, 0, MEM_RELEASE );
|
||||
#else
|
||||
MemAlloc_FreeAligned( m_pBase );
|
||||
#endif
|
||||
m_pBase = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
int CMemoryStack::GetSize()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return m_pCommitLimit - m_pBase;
|
||||
#else
|
||||
return m_maxSize;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::CommitTo( byte *pNextAlloc ) RESTRICT
|
||||
{
|
||||
#ifdef _X360
|
||||
if ( m_bPhysical )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
unsigned char * pNewCommitLimit = AlignValue( pNextAlloc, m_commitSize );
|
||||
unsigned commitSize = pNewCommitLimit - m_pCommitLimit;
|
||||
|
||||
if ( GetSize() )
|
||||
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
|
||||
|
||||
if( m_pCommitLimit + commitSize > m_pAllocLimit )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !VirtualAlloc( m_pCommitLimit, commitSize, VA_COMMIT_FLAGS, PAGE_READWRITE ) )
|
||||
{
|
||||
Assert( 0 );
|
||||
return false;
|
||||
}
|
||||
m_pCommitLimit = pNewCommitLimit;
|
||||
|
||||
if ( GetSize() )
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
return true;
|
||||
#else
|
||||
Assert( 0 );
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit )
|
||||
{
|
||||
void *pAllocPoint = m_pBase + mark;
|
||||
Assert( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc );
|
||||
|
||||
if ( pAllocPoint >= m_pBase && pAllocPoint < m_pNextAlloc )
|
||||
{
|
||||
if ( bDecommit )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
unsigned char *pDecommitPoint = AlignValue( (unsigned char *)pAllocPoint, m_commitSize );
|
||||
|
||||
if ( pDecommitPoint < m_pBase + m_minCommit )
|
||||
{
|
||||
pDecommitPoint = m_pBase + m_minCommit;
|
||||
}
|
||||
|
||||
unsigned decommitSize = m_pCommitLimit - pDecommitPoint;
|
||||
|
||||
if ( decommitSize > 0 )
|
||||
{
|
||||
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
|
||||
|
||||
VirtualFree( pDecommitPoint, decommitSize, MEM_DECOMMIT );
|
||||
m_pCommitLimit = pDecommitPoint;
|
||||
|
||||
if ( mark > 0 )
|
||||
{
|
||||
MemAlloc_RegisterExternalAllocation( CMemoryStack, GetBase(), GetSize() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
m_pNextAlloc = (unsigned char *)pAllocPoint;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeAll( bool bDecommit )
|
||||
{
|
||||
if ( m_pBase && m_pCommitLimit - m_pBase > 0 )
|
||||
{
|
||||
if ( bDecommit )
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
MemAlloc_RegisterExternalDeallocation( CMemoryStack, GetBase(), GetSize() );
|
||||
|
||||
VirtualFree( m_pBase, m_pCommitLimit - m_pBase, MEM_DECOMMIT );
|
||||
m_pCommitLimit = m_pBase;
|
||||
#endif
|
||||
}
|
||||
m_pNextAlloc = m_pBase;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Access( void **ppRegion, unsigned *pBytes )
|
||||
{
|
||||
*ppRegion = m_pBase;
|
||||
*pBytes = ( m_pNextAlloc - m_pBase);
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::PrintContents()
|
||||
{
|
||||
Msg( "Total used memory: %d\n", GetUsed() );
|
||||
Msg( "Total committed memory: %d\n", GetSize() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,274 +1,274 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: win32 dependant ASM code for CPU capability detection
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#if defined( _X360 ) || defined( WIN64 )
|
||||
|
||||
bool CheckMMXTechnology(void) { return false; }
|
||||
bool CheckSSETechnology(void) { return false; }
|
||||
bool CheckSSE2Technology(void) { return false; }
|
||||
bool Check3DNowTechnology(void) { return false; }
|
||||
|
||||
#elif defined( _WIN32 ) && !defined( _X360 )
|
||||
|
||||
#pragma optimize( "", off )
|
||||
#pragma warning( disable: 4800 ) //'int' : forcing value to bool 'true' or 'false' (performance warning)
|
||||
|
||||
// stuff from windows.h
|
||||
#ifndef EXCEPTION_EXECUTE_HANDLER
|
||||
#define EXCEPTION_EXECUTE_HANDLER 1
|
||||
#endif
|
||||
|
||||
bool CheckMMXTechnology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEDX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 1 // set up CPUID to return processor version and features
|
||||
// 0 = vendor string, 1 = version info, 2 = cache info
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEDX, edx // features returned in edx
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then certainly no MMX extensions.
|
||||
if (retval)
|
||||
{
|
||||
if (RegEDX & 0x800000) // bit 23 is set for MMX technology
|
||||
{
|
||||
__try
|
||||
{
|
||||
// try executing the MMX instruction "emms"
|
||||
_asm EMMS
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
retval = false; // processor supports CPUID but does not support MMX technology
|
||||
|
||||
// if retval == 0 here, it means the processor has MMX technology but
|
||||
// floating-point emulation is on; so MMX technology is unavailable
|
||||
}
|
||||
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CheckSSETechnology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEDX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
// Do we have support for the CPUID function?
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 1 // set up CPUID to return processor version and features
|
||||
// 0 = vendor string, 1 = version info, 2 = cache info
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEDX, edx // features returned in edx
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then certainly no SSE extensions.
|
||||
if (retval)
|
||||
{
|
||||
// Do we have support for SSE in this processor?
|
||||
if ( RegEDX & 0x2000000L ) // bit 25 is set for SSE technology
|
||||
{
|
||||
// Make sure that SSE is supported by executing an inline SSE instruction
|
||||
|
||||
// BUGBUG, FIXME - Visual C Version 6.0 does not support SSE inline code YET (No macros from Intel either)
|
||||
// Fix this if VC7 supports inline SSE instructinons like "xorps" as shown below.
|
||||
#if 1
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// Attempt execution of a SSE instruction to make sure OS supports SSE FPU context switches
|
||||
xorps xmm0, xmm0
|
||||
// This will work on Win2k+ (Including masking SSE FPU exception to "normalized" values)
|
||||
// This will work on Win98+ (But no "masking" of FPU exceptions provided)
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
#endif
|
||||
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
retval = false;
|
||||
}
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CheckSSE2Technology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEDX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
// Do we have support for the CPUID function?
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 1 // set up CPUID to return processor version and features
|
||||
// 0 = vendor string, 1 = version info, 2 = cache info
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEDX, edx // features returned in edx
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then certainly no SSE extensions.
|
||||
if (retval)
|
||||
{
|
||||
// Do we have support for SSE in this processor?
|
||||
if ( RegEDX & 0x04000000 ) // bit 26 is set for SSE2 technology
|
||||
{
|
||||
// Make sure that SSE is supported by executing an inline SSE instruction
|
||||
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// Attempt execution of a SSE2 instruction to make sure OS supports SSE FPU context switches
|
||||
xorpd xmm0, xmm0
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
retval = false;
|
||||
}
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool Check3DNowTechnology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEAX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
// First see if we can execute CPUID at all
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
// xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 0x80000000 // setup CPUID to return whether AMD >0x80000000 function are supported.
|
||||
// 0x80000000 = Highest 0x80000000+ function, 0x80000001 = 3DNow support
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEAX, eax // result returned in eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then there is definitely no 3DNow support
|
||||
if (retval)
|
||||
{
|
||||
// Are there any "higher" AMD CPUID functions?
|
||||
if (RegEAX > 0x80000000L )
|
||||
{
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
mov eax, 0x80000001 // setup to test for CPU features
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
shr edx, 31 // If bit 31 is set, we have 3DNow support!
|
||||
mov retval, edx // Save the return value for end of function
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// processor supports CPUID but does not support AMD CPUID functions
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#pragma optimize( "", on )
|
||||
|
||||
#endif // _WIN32
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: win32 dependant ASM code for CPU capability detection
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#if defined( _X360 ) || defined( WIN64 )
|
||||
|
||||
bool CheckMMXTechnology(void) { return false; }
|
||||
bool CheckSSETechnology(void) { return false; }
|
||||
bool CheckSSE2Technology(void) { return false; }
|
||||
bool Check3DNowTechnology(void) { return false; }
|
||||
|
||||
#elif defined( _WIN32 ) && !defined( _X360 )
|
||||
|
||||
#pragma optimize( "", off )
|
||||
#pragma warning( disable: 4800 ) //'int' : forcing value to bool 'true' or 'false' (performance warning)
|
||||
|
||||
// stuff from windows.h
|
||||
#ifndef EXCEPTION_EXECUTE_HANDLER
|
||||
#define EXCEPTION_EXECUTE_HANDLER 1
|
||||
#endif
|
||||
|
||||
bool CheckMMXTechnology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEDX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 1 // set up CPUID to return processor version and features
|
||||
// 0 = vendor string, 1 = version info, 2 = cache info
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEDX, edx // features returned in edx
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then certainly no MMX extensions.
|
||||
if (retval)
|
||||
{
|
||||
if (RegEDX & 0x800000) // bit 23 is set for MMX technology
|
||||
{
|
||||
__try
|
||||
{
|
||||
// try executing the MMX instruction "emms"
|
||||
_asm EMMS
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
retval = false; // processor supports CPUID but does not support MMX technology
|
||||
|
||||
// if retval == 0 here, it means the processor has MMX technology but
|
||||
// floating-point emulation is on; so MMX technology is unavailable
|
||||
}
|
||||
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CheckSSETechnology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEDX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
// Do we have support for the CPUID function?
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 1 // set up CPUID to return processor version and features
|
||||
// 0 = vendor string, 1 = version info, 2 = cache info
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEDX, edx // features returned in edx
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then certainly no SSE extensions.
|
||||
if (retval)
|
||||
{
|
||||
// Do we have support for SSE in this processor?
|
||||
if ( RegEDX & 0x2000000L ) // bit 25 is set for SSE technology
|
||||
{
|
||||
// Make sure that SSE is supported by executing an inline SSE instruction
|
||||
|
||||
// BUGBUG, FIXME - Visual C Version 6.0 does not support SSE inline code YET (No macros from Intel either)
|
||||
// Fix this if VC7 supports inline SSE instructinons like "xorps" as shown below.
|
||||
#if 1
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// Attempt execution of a SSE instruction to make sure OS supports SSE FPU context switches
|
||||
xorps xmm0, xmm0
|
||||
// This will work on Win2k+ (Including masking SSE FPU exception to "normalized" values)
|
||||
// This will work on Win98+ (But no "masking" of FPU exceptions provided)
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
#endif
|
||||
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
retval = false;
|
||||
}
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CheckSSE2Technology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEDX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
// Do we have support for the CPUID function?
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 1 // set up CPUID to return processor version and features
|
||||
// 0 = vendor string, 1 = version info, 2 = cache info
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEDX, edx // features returned in edx
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then certainly no SSE extensions.
|
||||
if (retval)
|
||||
{
|
||||
// Do we have support for SSE in this processor?
|
||||
if ( RegEDX & 0x04000000 ) // bit 26 is set for SSE2 technology
|
||||
{
|
||||
// Make sure that SSE is supported by executing an inline SSE instruction
|
||||
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
// Attempt execution of a SSE2 instruction to make sure OS supports SSE FPU context switches
|
||||
xorpd xmm0, xmm0
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
retval = false;
|
||||
}
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool Check3DNowTechnology(void)
|
||||
{
|
||||
int retval = true;
|
||||
unsigned int RegEAX = 0;
|
||||
|
||||
#ifdef CPUID
|
||||
_asm pushad;
|
||||
#endif
|
||||
|
||||
// First see if we can execute CPUID at all
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
#ifdef CPUID
|
||||
// xor edx, edx // Clue the compiler that EDX is about to be used.
|
||||
#endif
|
||||
mov eax, 0x80000000 // setup CPUID to return whether AMD >0x80000000 function are supported.
|
||||
// 0x80000000 = Highest 0x80000000+ function, 0x80000001 = 3DNow support
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
mov RegEAX, eax // result returned in eax
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
|
||||
// If CPUID not supported, then there is definitely no 3DNow support
|
||||
if (retval)
|
||||
{
|
||||
// Are there any "higher" AMD CPUID functions?
|
||||
if (RegEAX > 0x80000000L )
|
||||
{
|
||||
__try
|
||||
{
|
||||
_asm
|
||||
{
|
||||
mov eax, 0x80000001 // setup to test for CPU features
|
||||
CPUID // code bytes = 0fh, 0a2h
|
||||
shr edx, 31 // If bit 31 is set, we have 3DNow support!
|
||||
mov retval, edx // Save the return value for end of function
|
||||
}
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// processor supports CPUID but does not support AMD CPUID functions
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CPUID
|
||||
_asm popad;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#pragma optimize( "", on )
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: linux dependant ASM code for CPU capability detection
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#define cpuid(in,a,b,c,d) \
|
||||
asm("pushl %%ebx\n\t" "cpuid\n\t" "movl %%ebx,%%esi\n\t" "pop %%ebx": "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (in));
|
||||
|
||||
bool CheckMMXTechnology(void)
|
||||
{
|
||||
unsigned long eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x800000;
|
||||
}
|
||||
|
||||
bool CheckSSETechnology(void)
|
||||
{
|
||||
unsigned long eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x2000000L;
|
||||
}
|
||||
|
||||
bool CheckSSE2Technology(void)
|
||||
{
|
||||
unsigned long eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x04000000;
|
||||
}
|
||||
|
||||
bool Check3DNowTechnology(void)
|
||||
{
|
||||
unsigned long eax, unused;
|
||||
cpuid(0x80000000,eax,unused,unused,unused);
|
||||
|
||||
if ( eax > 0x80000000L )
|
||||
{
|
||||
cpuid(0x80000001,unused,unused,unused,eax);
|
||||
return ( eax & 1<<31 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: linux dependant ASM code for CPU capability detection
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#define cpuid(in,a,b,c,d) \
|
||||
asm("pushl %%ebx\n\t" "cpuid\n\t" "movl %%ebx,%%esi\n\t" "pop %%ebx": "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (in));
|
||||
|
||||
bool CheckMMXTechnology(void)
|
||||
{
|
||||
unsigned long eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x800000;
|
||||
}
|
||||
|
||||
bool CheckSSETechnology(void)
|
||||
{
|
||||
unsigned long eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x2000000L;
|
||||
}
|
||||
|
||||
bool CheckSSE2Technology(void)
|
||||
{
|
||||
unsigned long eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x04000000;
|
||||
}
|
||||
|
||||
bool Check3DNowTechnology(void)
|
||||
{
|
||||
unsigned long eax, unused;
|
||||
cpuid(0x80000000,eax,unused,unused,unused);
|
||||
|
||||
if ( eax > 0x80000000L )
|
||||
{
|
||||
cpuid(0x80000001,unused,unused,unused,eax);
|
||||
return ( eax & 1<<31 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,112 +1,112 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
/******************************************************************/
|
||||
|
||||
/* qsort.c -- Non-Recursive ANSI Quicksort function */
|
||||
|
||||
/* */
|
||||
|
||||
/* Public domain by Raymond Gardner, Englewood CO February 1991 */
|
||||
|
||||
/* */
|
||||
|
||||
/* Usage: */
|
||||
|
||||
/* qsort(base, nbr_elements, width_bytes, compare_function); */
|
||||
|
||||
/* void *base; */
|
||||
|
||||
/* size_t nbr_elements, width_bytes; */
|
||||
|
||||
/* int (*compare_function)(const void *, const void *); */
|
||||
|
||||
/* */
|
||||
|
||||
/* Sorts an array starting at base, of length nbr_elements, each */
|
||||
|
||||
/* element of size width_bytes, ordered via compare_function, */
|
||||
|
||||
/* which is called as (*compare_function)(ptr_to_element1, */
|
||||
|
||||
/* ptr_to_element2) and returns < 0 if element1 < element2, */
|
||||
|
||||
/* 0 if element1 = element2, > 0 if element1 > element2. */
|
||||
|
||||
/* Most refinements are due to R. Sedgewick. See "Implementing */
|
||||
|
||||
/* Quicksort Programs", Comm. ACM, Oct. 1978, and Corrigendum, */
|
||||
|
||||
/* Comm. ACM, June 1979. */
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
|
||||
|
||||
// modified to take (and use) a context object, ala Microsoft's qsort_s
|
||||
|
||||
// "extension" to the stdlib
|
||||
|
||||
|
||||
|
||||
#include <stddef.h> /* for size_t definition */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
** swap nbytes between a and b
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static void swap_bytes(char *a, char *b, size_t nbytes)
|
||||
|
||||
{
|
||||
|
||||
char tmp;
|
||||
|
||||
do {
|
||||
|
||||
tmp = *a; *a++ = *b; *b++ = tmp;
|
||||
|
||||
} while ( --nbytes );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define SWAP(a, b) (swap_bytes((char *)(a), (char *)(b), size))
|
||||
|
||||
|
||||
|
||||
#define COMP(ctx, a, b) ((*comp)((void *)ctx, (void *)(a), (void *)(b)))
|
||||
|
||||
|
||||
|
||||
#define T 7 /* subfiles of T or fewer elements will */
|
||||
|
||||
/* be sorted by a simple insertion sort */
|
||||
|
||||
/* Note! T must be at least 3 */
|
||||
|
||||
|
||||
|
||||
extern "C" void qsort_s(void *basep, size_t nelems, size_t size,
|
||||
|
||||
int (*comp)(void *, const void *, const void *),
|
||||
|
||||
void *ctx)
|
||||
|
||||
{
|
||||
|
||||
char *stack[40], **sp; /* stack and stack pointer */
|
||||
|
||||
char *i, *j, *limit; /* scan and limit pointers */
|
||||
|
||||
size_t thresh; /* size of T elements in bytes */
|
||||
|
||||
char *base; /* base pointer as char * */
|
||||
|
||||
|
||||
|
||||
base = (char *)basep; /* set up char * base pointer */
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
/******************************************************************/
|
||||
/* qsort.c -- Non-Recursive ANSI Quicksort function */
|
||||
/* */
|
||||
/* Public domain by Raymond Gardner, Englewood CO February 1991 */
|
||||
/* */
|
||||
/* Usage: */
|
||||
/* qsort(base, nbr_elements, width_bytes, compare_function); */
|
||||
/* void *base; */
|
||||
/* size_t nbr_elements, width_bytes; */
|
||||
/* int (*compare_function)(const void *, const void *); */
|
||||
/* */
|
||||
/* Sorts an array starting at base, of length nbr_elements, each */
|
||||
/* element of size width_bytes, ordered via compare_function, */
|
||||
/* which is called as (*compare_function)(ptr_to_element1, */
|
||||
/* ptr_to_element2) and returns < 0 if element1 < element2, */
|
||||
/* 0 if element1 = element2, > 0 if element1 > element2. */
|
||||
/* Most refinements are due to R. Sedgewick. See "Implementing */
|
||||
/* Quicksort Programs", Comm. ACM, Oct. 1978, and Corrigendum, */
|
||||
/* Comm. ACM, June 1979. */
|
||||
/******************************************************************/
|
||||
|
||||
// modified to take (and use) a context object, ala Microsoft's qsort_s
|
||||
// "extension" to the stdlib
|
||||
|
||||
#include <stddef.h> /* for size_t definition */
|
||||
|
||||
/*
|
||||
** swap nbytes between a and b
|
||||
*/
|
||||
|
||||
static void swap_bytes(char *a, char *b, size_t nbytes)
|
||||
{
|
||||
char tmp;
|
||||
do {
|
||||
tmp = *a; *a++ = *b; *b++ = tmp;
|
||||
} while ( --nbytes );
|
||||
}
|
||||
|
||||
#define SWAP(a, b) (swap_bytes((char *)(a), (char *)(b), size))
|
||||
|
||||
#define COMP(ctx, a, b) ((*comp)((void *)ctx, (void *)(a), (void *)(b)))
|
||||
|
||||
#define T 7 /* subfiles of T or fewer elements will */
|
||||
/* be sorted by a simple insertion sort */
|
||||
/* Note! T must be at least 3 */
|
||||
|
||||
extern "C" void qsort_s(void *basep, size_t nelems, size_t size,
|
||||
int (*comp)(void *, const void *, const void *),
|
||||
void *ctx)
|
||||
{
|
||||
char *stack[40], **sp; /* stack and stack pointer */
|
||||
char *i, *j, *limit; /* scan and limit pointers */
|
||||
size_t thresh; /* size of T elements in bytes */
|
||||
char *base; /* base pointer as char * */
|
||||
|
||||
base = (char *)basep; /* set up char * base pointer */
|
||||
thresh = T * size; /* init threshold */
|
||||
sp = stack; /* init stack pointer */
|
||||
limit = base + nelems * size;/* pointer past end of array */
|
||||
for ( ;; ) { /* repeat until break... */
|
||||
if ( limit - base > thresh ) { /* if more than T elements */
|
||||
/* swap base with middle */
|
||||
SWAP((((limit-base)/size)/2)*size+base, base);
|
||||
i = base + size; /* i scans left to right */
|
||||
j = limit - size; /* j scans right to left */
|
||||
if ( COMP(ctx, i, j) > 0 ) /* Sedgewick's */
|
||||
SWAP(i, j); /* three-element sort */
|
||||
if ( COMP(ctx, base, j) > 0 )/* sets things up */
|
||||
SWAP(base, j); /* so that */
|
||||
if ( COMP(ctx, i, base) > 0 )/* *i <= *base <= *j */
|
||||
SWAP(i, base); /* *base is pivot element */
|
||||
for ( ;; ) { /* loop until break */
|
||||
do /* move i right */
|
||||
i += size; /* until *i >= pivot */
|
||||
while ( COMP(ctx, i, base) < 0 );
|
||||
do /* move j left */
|
||||
j -= size; /* until *j <= pivot */
|
||||
while ( COMP(ctx, j, base) > 0 );
|
||||
if ( i > j ) /* if pointers crossed */
|
||||
break; /* break loop */
|
||||
SWAP(i, j); /* else swap elements, keep scanning*/
|
||||
}
|
||||
SWAP(base, j); /* move pivot into correct place */
|
||||
if ( j - base > limit - i ) { /* if left subfile larger */
|
||||
sp[0] = base; /* stack left subfile base */
|
||||
sp[1] = j; /* and limit */
|
||||
base = i; /* sort the right subfile */
|
||||
} else { /* else right subfile larger*/
|
||||
sp[0] = i; /* stack right subfile base */
|
||||
sp[1] = limit; /* and limit */
|
||||
limit = j; /* sort the left subfile */
|
||||
}
|
||||
sp += 2; /* increment stack pointer */
|
||||
} else { /* else subfile is small, use insertion sort */
|
||||
for ( j = base, i = j+size; i < limit; j = i, i += size )
|
||||
for ( ; COMP(ctx, j, j+size) > 0; j -= size ) {
|
||||
SWAP(j, j+size);
|
||||
if ( j == base )
|
||||
break;
|
||||
}
|
||||
if ( sp != stack ) { /* if any entries on stack */
|
||||
sp -= 2; /* pop the base and limit */
|
||||
base = sp[0];
|
||||
limit = sp[1];
|
||||
} else /* else stack empty, done */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "rangecheckedvar.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
bool g_bDoRangeChecks = true;
|
||||
|
||||
|
||||
static int g_nDisables = 0;
|
||||
|
||||
|
||||
CDisableRangeChecks::CDisableRangeChecks()
|
||||
{
|
||||
if ( !ThreadInMainThread() )
|
||||
return;
|
||||
g_nDisables++;
|
||||
g_bDoRangeChecks = false;
|
||||
}
|
||||
|
||||
|
||||
CDisableRangeChecks::~CDisableRangeChecks()
|
||||
{
|
||||
if ( !ThreadInMainThread() )
|
||||
return;
|
||||
Assert( g_nDisables > 0 );
|
||||
--g_nDisables;
|
||||
if ( g_nDisables == 0 )
|
||||
{
|
||||
g_bDoRangeChecks = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "rangecheckedvar.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
bool g_bDoRangeChecks = true;
|
||||
|
||||
|
||||
static int g_nDisables = 0;
|
||||
|
||||
|
||||
CDisableRangeChecks::CDisableRangeChecks()
|
||||
{
|
||||
if ( !ThreadInMainThread() )
|
||||
return;
|
||||
g_nDisables++;
|
||||
g_bDoRangeChecks = false;
|
||||
}
|
||||
|
||||
|
||||
CDisableRangeChecks::~CDisableRangeChecks()
|
||||
{
|
||||
if ( !ThreadInMainThread() )
|
||||
return;
|
||||
Assert( g_nDisables > 0 );
|
||||
--g_nDisables;
|
||||
if ( g_nDisables == 0 )
|
||||
{
|
||||
g_bDoRangeChecks = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "tier1/reliabletimer.h"
|
||||
|
||||
int64 CReliableTimer::sm_nPerformanceFrequency = 0;
|
||||
bool CReliableTimer::sm_bUseQPC = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winlite.h"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CReliableTimer::CReliableTimer()
|
||||
{
|
||||
m_nPerformanceCounterStart = 0;
|
||||
m_nPerformanceCounterEnd = 0;
|
||||
m_nPerformanceCounterLimit = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
// calculate performance frequency the first time we use a timer
|
||||
if ( 0 == sm_nPerformanceFrequency )
|
||||
{
|
||||
// Are we on a bad CPU?
|
||||
sm_bUseQPC = false; // todo
|
||||
const CPUInformation &cpu = *GetCPUInformation();
|
||||
sm_bUseQPC = ( ( 0 == Q_stricmp( cpu.m_szProcessorID, "AuthenticAMD" ) )
|
||||
&& ( cpu.m_nPhysicalProcessors > 1 )
|
||||
&& !cpu.m_bSSE41 );
|
||||
|
||||
if ( sm_bUseQPC )
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceFrequency( &li );
|
||||
sm_nPerformanceFrequency = li.QuadPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
sm_nPerformanceFrequency = g_ClockSpeed;
|
||||
}
|
||||
}
|
||||
#elif defined(_PS3)
|
||||
// On PowerPC, the time base register increment frequency is implementation dependent, and doesn't have to be constant.
|
||||
// On PS3, measured it to be just shy of 80Mhz on the PPU and doesn't seem to change
|
||||
if ( sm_nPerformanceFrequency == 0 )
|
||||
sm_nPerformanceFrequency = sys_time_get_timebase_frequency();
|
||||
#else
|
||||
// calculate performance frequency the first time we use a timer
|
||||
if ( 0 == sm_nPerformanceFrequency )
|
||||
{
|
||||
sm_nPerformanceFrequency = g_ClockSpeed;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns current QueryPerformanceCounter value
|
||||
//-----------------------------------------------------------------------------
|
||||
int64 CReliableTimer::GetPerformanceCountNow()
|
||||
{
|
||||
//VPROF_BUDGET( "CReliableTimer::GetPerformanceCountNow", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED );
|
||||
#ifdef _WIN32
|
||||
if ( sm_bUseQPC )
|
||||
{
|
||||
LARGE_INTEGER li = {0};
|
||||
QueryPerformanceCounter( &li );
|
||||
return li.QuadPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCycleCount CycleCount;
|
||||
CycleCount.Sample();
|
||||
return CycleCount.GetLongCycles();
|
||||
}
|
||||
#elif defined( _PS3 )
|
||||
// use handy macro to grab tb
|
||||
uint64 ulNow;
|
||||
SYS_TIMEBASE_GET( ulNow );
|
||||
return ulNow;
|
||||
#else
|
||||
uint64 un64;
|
||||
__asm__ __volatile__ (
|
||||
"rdtsc\n\t"
|
||||
: "=A" (un64) );
|
||||
return (int64)un64;
|
||||
#endif
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "tier1/reliabletimer.h"
|
||||
|
||||
int64 CReliableTimer::sm_nPerformanceFrequency = 0;
|
||||
bool CReliableTimer::sm_bUseQPC = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winlite.h"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CReliableTimer::CReliableTimer()
|
||||
{
|
||||
m_nPerformanceCounterStart = 0;
|
||||
m_nPerformanceCounterEnd = 0;
|
||||
m_nPerformanceCounterLimit = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
// calculate performance frequency the first time we use a timer
|
||||
if ( 0 == sm_nPerformanceFrequency )
|
||||
{
|
||||
// Are we on a bad CPU?
|
||||
sm_bUseQPC = false; // todo
|
||||
const CPUInformation &cpu = *GetCPUInformation();
|
||||
sm_bUseQPC = ( ( 0 == Q_stricmp( cpu.m_szProcessorID, "AuthenticAMD" ) )
|
||||
&& ( cpu.m_nPhysicalProcessors > 1 )
|
||||
&& !cpu.m_bSSE41 );
|
||||
|
||||
if ( sm_bUseQPC )
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceFrequency( &li );
|
||||
sm_nPerformanceFrequency = li.QuadPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
sm_nPerformanceFrequency = g_ClockSpeed;
|
||||
}
|
||||
}
|
||||
#elif defined(_PS3)
|
||||
// On PowerPC, the time base register increment frequency is implementation dependent, and doesn't have to be constant.
|
||||
// On PS3, measured it to be just shy of 80Mhz on the PPU and doesn't seem to change
|
||||
if ( sm_nPerformanceFrequency == 0 )
|
||||
sm_nPerformanceFrequency = sys_time_get_timebase_frequency();
|
||||
#else
|
||||
// calculate performance frequency the first time we use a timer
|
||||
if ( 0 == sm_nPerformanceFrequency )
|
||||
{
|
||||
sm_nPerformanceFrequency = g_ClockSpeed;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns current QueryPerformanceCounter value
|
||||
//-----------------------------------------------------------------------------
|
||||
int64 CReliableTimer::GetPerformanceCountNow()
|
||||
{
|
||||
//VPROF_BUDGET( "CReliableTimer::GetPerformanceCountNow", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED );
|
||||
#ifdef _WIN32
|
||||
if ( sm_bUseQPC )
|
||||
{
|
||||
LARGE_INTEGER li = {0};
|
||||
QueryPerformanceCounter( &li );
|
||||
return li.QuadPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCycleCount CycleCount;
|
||||
CycleCount.Sample();
|
||||
return CycleCount.GetLongCycles();
|
||||
}
|
||||
#elif defined( _PS3 )
|
||||
// use handy macro to grab tb
|
||||
uint64 ulNow;
|
||||
SYS_TIMEBASE_GET( ulNow );
|
||||
return ulNow;
|
||||
#else
|
||||
uint64 un64;
|
||||
__asm__ __volatile__ (
|
||||
"rdtsc\n\t"
|
||||
: "=A" (un64) );
|
||||
return (int64)un64;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,150 +1,150 @@
|
||||
// Copyright 2008 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Internals shared between the Snappy implementation and its unittest.
|
||||
|
||||
#ifndef UTIL_SNAPPY_SNAPPY_INTERNAL_H_
|
||||
#define UTIL_SNAPPY_SNAPPY_INTERNAL_H_
|
||||
|
||||
#include "snappy-stubs-internal.h"
|
||||
|
||||
namespace snappy {
|
||||
namespace internal {
|
||||
|
||||
class WorkingMemory {
|
||||
public:
|
||||
WorkingMemory() : large_table_(NULL) { }
|
||||
~WorkingMemory() { delete[] large_table_; }
|
||||
|
||||
// Allocates and clears a hash table using memory in "*this",
|
||||
// stores the number of buckets in "*table_size" and returns a pointer to
|
||||
// the base of the hash table.
|
||||
uint16* GetHashTable(size_t input_size, int* table_size);
|
||||
|
||||
private:
|
||||
uint16 small_table_[1<<10]; // 2KB
|
||||
uint16* large_table_; // Allocated only when needed
|
||||
|
||||
SNAPPY_DISALLOW_COPY_AND_ASSIGN(WorkingMemory);
|
||||
};
|
||||
|
||||
// Flat array compression that does not emit the "uncompressed length"
|
||||
// prefix. Compresses "input" string to the "*op" buffer.
|
||||
//
|
||||
// REQUIRES: "input_length <= kBlockSize"
|
||||
// REQUIRES: "op" points to an array of memory that is at least
|
||||
// "MaxCompressedLength(input_length)" in size.
|
||||
// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
|
||||
// REQUIRES: "table_size" is a power of two
|
||||
//
|
||||
// Returns an "end" pointer into "op" buffer.
|
||||
// "end - op" is the compressed size of "input".
|
||||
char* CompressFragment(const char* input,
|
||||
size_t input_length,
|
||||
char* op,
|
||||
uint16* table,
|
||||
const int table_size);
|
||||
|
||||
// Return the largest n such that
|
||||
//
|
||||
// s1[0,n-1] == s2[0,n-1]
|
||||
// and n <= (s2_limit - s2).
|
||||
//
|
||||
// Does not read *s2_limit or beyond.
|
||||
// Does not read *(s1 + (s2_limit - s2)) or beyond.
|
||||
// Requires that s2_limit >= s2.
|
||||
//
|
||||
// Separate implementation for x86_64, for speed. Uses the fact that
|
||||
// x86_64 is little endian.
|
||||
#if defined(ARCH_K8)
|
||||
static inline int FindMatchLength(const char* s1,
|
||||
const char* s2,
|
||||
const char* s2_limit) {
|
||||
DCHECK_GE(s2_limit, s2);
|
||||
int matched = 0;
|
||||
|
||||
// Find out how long the match is. We loop over the data 64 bits at a
|
||||
// time until we find a 64-bit block that doesn't match; then we find
|
||||
// the first non-matching bit and use that to calculate the total
|
||||
// length of the match.
|
||||
while (PREDICT_TRUE(s2 <= s2_limit - 8)) {
|
||||
if (PREDICT_FALSE(UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched))) {
|
||||
s2 += 8;
|
||||
matched += 8;
|
||||
} else {
|
||||
// On current (mid-2008) Opteron models there is a 3% more
|
||||
// efficient code sequence to find the first non-matching byte.
|
||||
// However, what follows is ~10% better on Intel Core 2 and newer,
|
||||
// and we expect AMD's bsf instruction to improve.
|
||||
uint64 x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched);
|
||||
int matching_bits = Bits::FindLSBSetNonZero64(x);
|
||||
matched += matching_bits >> 3;
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
while (PREDICT_TRUE(s2 < s2_limit)) {
|
||||
if (PREDICT_TRUE(s1[matched] == *s2)) {
|
||||
++s2;
|
||||
++matched;
|
||||
} else {
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
#else
|
||||
static inline int FindMatchLength(const char* s1,
|
||||
const char* s2,
|
||||
const char* s2_limit) {
|
||||
// Implementation based on the x86-64 version, above.
|
||||
DCHECK_GE(s2_limit, s2);
|
||||
int matched = 0;
|
||||
|
||||
while (s2 <= s2_limit - 4 &&
|
||||
UNALIGNED_LOAD32(s2) == UNALIGNED_LOAD32(s1 + matched)) {
|
||||
s2 += 4;
|
||||
matched += 4;
|
||||
}
|
||||
if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 4) {
|
||||
uint32 x = UNALIGNED_LOAD32(s2) ^ UNALIGNED_LOAD32(s1 + matched);
|
||||
int matching_bits = Bits::FindLSBSetNonZero(x);
|
||||
matched += matching_bits >> 3;
|
||||
} else {
|
||||
while ((s2 < s2_limit) && (s1[matched] == *s2)) {
|
||||
++s2;
|
||||
++matched;
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace snappy
|
||||
|
||||
#endif // UTIL_SNAPPY_SNAPPY_INTERNAL_H_
|
||||
// Copyright 2008 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Internals shared between the Snappy implementation and its unittest.
|
||||
|
||||
#ifndef UTIL_SNAPPY_SNAPPY_INTERNAL_H_
|
||||
#define UTIL_SNAPPY_SNAPPY_INTERNAL_H_
|
||||
|
||||
#include "snappy-stubs-internal.h"
|
||||
|
||||
namespace snappy {
|
||||
namespace internal {
|
||||
|
||||
class WorkingMemory {
|
||||
public:
|
||||
WorkingMemory() : large_table_(NULL) { }
|
||||
~WorkingMemory() { delete[] large_table_; }
|
||||
|
||||
// Allocates and clears a hash table using memory in "*this",
|
||||
// stores the number of buckets in "*table_size" and returns a pointer to
|
||||
// the base of the hash table.
|
||||
uint16* GetHashTable(size_t input_size, int* table_size);
|
||||
|
||||
private:
|
||||
uint16 small_table_[1<<10]; // 2KB
|
||||
uint16* large_table_; // Allocated only when needed
|
||||
|
||||
SNAPPY_DISALLOW_COPY_AND_ASSIGN(WorkingMemory);
|
||||
};
|
||||
|
||||
// Flat array compression that does not emit the "uncompressed length"
|
||||
// prefix. Compresses "input" string to the "*op" buffer.
|
||||
//
|
||||
// REQUIRES: "input_length <= kBlockSize"
|
||||
// REQUIRES: "op" points to an array of memory that is at least
|
||||
// "MaxCompressedLength(input_length)" in size.
|
||||
// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
|
||||
// REQUIRES: "table_size" is a power of two
|
||||
//
|
||||
// Returns an "end" pointer into "op" buffer.
|
||||
// "end - op" is the compressed size of "input".
|
||||
char* CompressFragment(const char* input,
|
||||
size_t input_length,
|
||||
char* op,
|
||||
uint16* table,
|
||||
const int table_size);
|
||||
|
||||
// Return the largest n such that
|
||||
//
|
||||
// s1[0,n-1] == s2[0,n-1]
|
||||
// and n <= (s2_limit - s2).
|
||||
//
|
||||
// Does not read *s2_limit or beyond.
|
||||
// Does not read *(s1 + (s2_limit - s2)) or beyond.
|
||||
// Requires that s2_limit >= s2.
|
||||
//
|
||||
// Separate implementation for x86_64, for speed. Uses the fact that
|
||||
// x86_64 is little endian.
|
||||
#if defined(ARCH_K8)
|
||||
static inline int FindMatchLength(const char* s1,
|
||||
const char* s2,
|
||||
const char* s2_limit) {
|
||||
DCHECK_GE(s2_limit, s2);
|
||||
int matched = 0;
|
||||
|
||||
// Find out how long the match is. We loop over the data 64 bits at a
|
||||
// time until we find a 64-bit block that doesn't match; then we find
|
||||
// the first non-matching bit and use that to calculate the total
|
||||
// length of the match.
|
||||
while (PREDICT_TRUE(s2 <= s2_limit - 8)) {
|
||||
if (PREDICT_FALSE(UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched))) {
|
||||
s2 += 8;
|
||||
matched += 8;
|
||||
} else {
|
||||
// On current (mid-2008) Opteron models there is a 3% more
|
||||
// efficient code sequence to find the first non-matching byte.
|
||||
// However, what follows is ~10% better on Intel Core 2 and newer,
|
||||
// and we expect AMD's bsf instruction to improve.
|
||||
uint64 x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched);
|
||||
int matching_bits = Bits::FindLSBSetNonZero64(x);
|
||||
matched += matching_bits >> 3;
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
while (PREDICT_TRUE(s2 < s2_limit)) {
|
||||
if (PREDICT_TRUE(s1[matched] == *s2)) {
|
||||
++s2;
|
||||
++matched;
|
||||
} else {
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
#else
|
||||
static inline int FindMatchLength(const char* s1,
|
||||
const char* s2,
|
||||
const char* s2_limit) {
|
||||
// Implementation based on the x86-64 version, above.
|
||||
DCHECK_GE(s2_limit, s2);
|
||||
int matched = 0;
|
||||
|
||||
while (s2 <= s2_limit - 4 &&
|
||||
UNALIGNED_LOAD32(s2) == UNALIGNED_LOAD32(s1 + matched)) {
|
||||
s2 += 4;
|
||||
matched += 4;
|
||||
}
|
||||
if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 4) {
|
||||
uint32 x = UNALIGNED_LOAD32(s2) ^ UNALIGNED_LOAD32(s1 + matched);
|
||||
int matching_bits = Bits::FindLSBSetNonZero(x);
|
||||
matched += matching_bits >> 3;
|
||||
} else {
|
||||
while ((s2 < s2_limit) && (s1[matched] == *s2)) {
|
||||
++s2;
|
||||
++matched;
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace snappy
|
||||
|
||||
#endif // UTIL_SNAPPY_SNAPPY_INTERNAL_H_
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "snappy-sinksource.h"
|
||||
|
||||
namespace snappy {
|
||||
|
||||
Source::~Source() { }
|
||||
|
||||
Sink::~Sink() { }
|
||||
|
||||
char* Sink::GetAppendBuffer(size_t, char* scratch) {
|
||||
return scratch;
|
||||
}
|
||||
|
||||
ByteArraySource::~ByteArraySource() { }
|
||||
|
||||
size_t ByteArraySource::Available() const { return left_; }
|
||||
|
||||
const char* ByteArraySource::Peek(size_t* len) {
|
||||
*len = left_;
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
void ByteArraySource::Skip(size_t n) {
|
||||
left_ -= n;
|
||||
ptr_ += n;
|
||||
}
|
||||
|
||||
UncheckedByteArraySink::~UncheckedByteArraySink() { }
|
||||
|
||||
void UncheckedByteArraySink::Append(const char* data, size_t n) {
|
||||
// Do no copying if the caller filled in the result of GetAppendBuffer()
|
||||
if (data != dest_) {
|
||||
memcpy(dest_, data, n);
|
||||
}
|
||||
dest_ += n;
|
||||
}
|
||||
|
||||
char* UncheckedByteArraySink::GetAppendBuffer(size_t, char*) {
|
||||
return dest_;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "snappy-sinksource.h"
|
||||
|
||||
namespace snappy {
|
||||
|
||||
Source::~Source() { }
|
||||
|
||||
Sink::~Sink() { }
|
||||
|
||||
char* Sink::GetAppendBuffer(size_t, char* scratch) {
|
||||
return scratch;
|
||||
}
|
||||
|
||||
ByteArraySource::~ByteArraySource() { }
|
||||
|
||||
size_t ByteArraySource::Available() const { return left_; }
|
||||
|
||||
const char* ByteArraySource::Peek(size_t* len) {
|
||||
*len = left_;
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
void ByteArraySource::Skip(size_t n) {
|
||||
left_ -= n;
|
||||
ptr_ += n;
|
||||
}
|
||||
|
||||
UncheckedByteArraySink::~UncheckedByteArraySink() { }
|
||||
|
||||
void UncheckedByteArraySink::Append(const char* data, size_t n) {
|
||||
// Do no copying if the caller filled in the result of GetAppendBuffer()
|
||||
if (data != dest_) {
|
||||
memcpy(dest_, data, n);
|
||||
}
|
||||
dest_ += n;
|
||||
}
|
||||
|
||||
char* UncheckedByteArraySink::GetAppendBuffer(size_t, char*) {
|
||||
return dest_;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <algorithm>
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4530) // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
|
||||
#endif //_WIN32
|
||||
#include <string>
|
||||
|
||||
#include "snappy-stubs-internal.h"
|
||||
|
||||
namespace snappy {
|
||||
|
||||
void Varint::Append32(string* s, uint32 value) {
|
||||
char buf[Varint::kMax32];
|
||||
const char* p = Varint::Encode32(buf, value);
|
||||
s->append(buf, p - buf);
|
||||
}
|
||||
|
||||
} // namespace snappy
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <algorithm>
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4530) // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
|
||||
#endif //_WIN32
|
||||
#include <string>
|
||||
|
||||
#include "snappy-stubs-internal.h"
|
||||
|
||||
namespace snappy {
|
||||
|
||||
void Varint::Append32(string* s, uint32 value) {
|
||||
char buf[Varint::kMax32];
|
||||
const char* p = Varint::Encode32(buf, value);
|
||||
s->append(buf, p - buf);
|
||||
}
|
||||
|
||||
} // namespace snappy
|
||||
|
||||
@@ -1,496 +1,496 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Various stubs for the open-source version of Snappy.
|
||||
|
||||
#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_
|
||||
#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "tier0/platform.h"
|
||||
|
||||
// don't use iostream, this make us fail to run under OS X 10.5
|
||||
//#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_SYS_MMAN
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
// Enable 64-bit optimized versions of some routines.
|
||||
#define ARCH_K8 1
|
||||
|
||||
#endif
|
||||
|
||||
// Needed by OS X, among others.
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
// Pull in std::min, std::ostream, and the likes. This is safe because this
|
||||
// header file is never used from any public header files.
|
||||
using namespace std;
|
||||
|
||||
// We only define ARRAYSIZE if it isn't already defined, because this definition
|
||||
// is not very good.
|
||||
#ifndef ARRAYSIZE
|
||||
// The size of an array, if known at compile-time.
|
||||
// Will give unexpected results if used on a pointer.
|
||||
#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||
#endif
|
||||
|
||||
// Static prediction hints.
|
||||
#ifdef HAVE_BUILTIN_EXPECT
|
||||
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||||
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||||
#else
|
||||
#define PREDICT_FALSE(x) x
|
||||
#define PREDICT_TRUE(x) x
|
||||
#endif
|
||||
|
||||
// This is only used for recomputing the tag byte table used during
|
||||
// decompression; for simplicity we just remove it from the open-source
|
||||
// version (anyone who wants to regenerate it can just do the call
|
||||
// themselves within main()).
|
||||
#define DEFINE_bool(flag_name, default_value, description) \
|
||||
bool FLAGS_ ## flag_name = default_value;
|
||||
#define DECLARE_bool(flag_name) \
|
||||
extern bool FLAGS_ ## flag_name;
|
||||
#define REGISTER_MODULE_INITIALIZER(name, code)
|
||||
|
||||
#define SNAPPY_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
namespace snappy {
|
||||
|
||||
static const uint32 kuint32max = static_cast<uint32>(0xFFFFFFFF);
|
||||
static const int64 kint64max = static_cast<int64>(0x7FFFFFFFFFFFFFFFLL);
|
||||
|
||||
// Logging.
|
||||
|
||||
#define LOG(level) LogMessage()
|
||||
#define VLOG(level) true ? (void)0 : \
|
||||
snappy::LogMessageVoidify() & snappy::LogMessage()
|
||||
|
||||
class LogMessage {
|
||||
public:
|
||||
LogMessage() { }
|
||||
~LogMessage() {
|
||||
fprintf( stderr, "\n" );
|
||||
//cerr << endl;
|
||||
}
|
||||
|
||||
LogMessage& operator<<(const std::string& msg) {
|
||||
//cerr << msg;
|
||||
fprintf( stderr, "%s", msg.c_str() );
|
||||
|
||||
return *this;
|
||||
}
|
||||
LogMessage& operator<<(int x) {
|
||||
fprintf( stderr, "%d", x );
|
||||
//cerr << x;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// Asserts, both versions activated in debug mode only,
|
||||
// and ones that are always active.
|
||||
|
||||
#define CRASH_UNLESS(condition) \
|
||||
PREDICT_TRUE(condition) ? (void)0 : \
|
||||
snappy::LogMessageVoidify() & snappy::LogMessageCrash()
|
||||
|
||||
class LogMessageCrash : public LogMessage {
|
||||
public:
|
||||
LogMessageCrash() { }
|
||||
#if _MSC_VER == 1700
|
||||
// Bogus warning from VS 2012:
|
||||
// warning C4722: 'snappy::LogMessageCrash::~LogMessageCrash' : destructor never returns, potential memory leak
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4722)
|
||||
#endif
|
||||
~LogMessageCrash() {
|
||||
fprintf( stderr, "\n" );
|
||||
// cerr << endl;
|
||||
abort();
|
||||
}
|
||||
};
|
||||
#if _MSC_VER == 1700
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// This class is used to explicitly ignore values in the conditional
|
||||
// logging macros. This avoids compiler warnings like "value computed
|
||||
// is not used" and "statement has no effect".
|
||||
|
||||
class LogMessageVoidify {
|
||||
public:
|
||||
LogMessageVoidify() { }
|
||||
// This has to be an operator with a precedence lower than << but
|
||||
// higher than ?:
|
||||
void operator&(const LogMessage&) { }
|
||||
};
|
||||
|
||||
#define CHECK(cond) CRASH_UNLESS(cond)
|
||||
#define CHECK_LE(a, b) CRASH_UNLESS((a) <= (b))
|
||||
#define CHECK_GE(a, b) CRASH_UNLESS((a) >= (b))
|
||||
#define CHECK_EQ(a, b) CRASH_UNLESS((a) == (b))
|
||||
#define CHECK_NE(a, b) CRASH_UNLESS((a) != (b))
|
||||
#define CHECK_LT(a, b) CRASH_UNLESS((a) < (b))
|
||||
#define CHECK_GT(a, b) CRASH_UNLESS((a) > (b))
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#define DCHECK(cond) CRASH_UNLESS(true)
|
||||
#define DCHECK_LE(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_GE(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_EQ(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_NE(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_LT(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_GT(a, b) CRASH_UNLESS(true)
|
||||
|
||||
#else
|
||||
|
||||
#define DCHECK(cond) CHECK(cond)
|
||||
#define DCHECK_LE(a, b) CHECK_LE(a, b)
|
||||
#define DCHECK_GE(a, b) CHECK_GE(a, b)
|
||||
#define DCHECK_EQ(a, b) CHECK_EQ(a, b)
|
||||
#define DCHECK_NE(a, b) CHECK_NE(a, b)
|
||||
#define DCHECK_LT(a, b) CHECK_LT(a, b)
|
||||
#define DCHECK_GT(a, b) CHECK_GT(a, b)
|
||||
|
||||
#endif
|
||||
|
||||
// Potentially unaligned loads and stores.
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
|
||||
|
||||
#define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
|
||||
#define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
|
||||
#define UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
|
||||
|
||||
#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
|
||||
#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
|
||||
#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val))
|
||||
|
||||
#else
|
||||
|
||||
// These functions are provided for architectures that don't support
|
||||
// unaligned loads and stores.
|
||||
|
||||
inline uint16 UNALIGNED_LOAD16(const void *p) {
|
||||
uint16 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint32 UNALIGNED_LOAD32(const void *p) {
|
||||
uint32 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint64 UNALIGNED_LOAD64(const void *p) {
|
||||
uint64 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline void UNALIGNED_STORE16(void *p, uint16 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void UNALIGNED_STORE32(void *p, uint32 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void UNALIGNED_STORE64(void *p, uint64 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// The following guarantees declaration of the byte swap functions.
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h>
|
||||
#define bswap_16(x) _byteswap_ushort(x)
|
||||
#define bswap_32(x) _byteswap_ulong(x)
|
||||
#define bswap_64(x) _byteswap_uint64(x)
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// Mac OS X / Darwin features
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16(x) OSSwapInt16(x)
|
||||
#define bswap_32(x) OSSwapInt32(x)
|
||||
#define bswap_64(x) OSSwapInt64(x)
|
||||
|
||||
#else
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#endif // WORDS_BIGENDIAN
|
||||
|
||||
// Convert to little-endian storage, opposite of network format.
|
||||
// Convert x from host to little endian: x = LittleEndian.FromHost(x);
|
||||
// convert x from little endian to host: x = LittleEndian.ToHost(x);
|
||||
//
|
||||
// Store values into unaligned memory converting to little endian order:
|
||||
// LittleEndian.Store16(p, x);
|
||||
//
|
||||
// Load unaligned values stored in little endian converting to host order:
|
||||
// x = LittleEndian.Load16(p);
|
||||
class LittleEndian {
|
||||
public:
|
||||
// Conversion functions.
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
static uint16 FromHost16(uint16 x) { return bswap_16(x); }
|
||||
static uint16 ToHost16(uint16 x) { return bswap_16(x); }
|
||||
|
||||
static uint32 FromHost32(uint32 x) { return bswap_32(x); }
|
||||
static uint32 ToHost32(uint32 x) { return bswap_32(x); }
|
||||
|
||||
static bool IsLittleEndian() { return false; }
|
||||
|
||||
#else // !defined(WORDS_BIGENDIAN)
|
||||
|
||||
static uint16 FromHost16(uint16 x) { return x; }
|
||||
static uint16 ToHost16(uint16 x) { return x; }
|
||||
|
||||
static uint32 FromHost32(uint32 x) { return x; }
|
||||
static uint32 ToHost32(uint32 x) { return x; }
|
||||
|
||||
static bool IsLittleEndian() { return true; }
|
||||
|
||||
#endif // !defined(WORDS_BIGENDIAN)
|
||||
|
||||
// Functions to do unaligned loads and stores in little-endian order.
|
||||
static uint16 Load16(const void *p) {
|
||||
return ToHost16(UNALIGNED_LOAD16(p));
|
||||
}
|
||||
|
||||
static void Store16(void *p, uint16 v) {
|
||||
UNALIGNED_STORE16(p, FromHost16(v));
|
||||
}
|
||||
|
||||
static uint32 Load32(const void *p) {
|
||||
return ToHost32(UNALIGNED_LOAD32(p));
|
||||
}
|
||||
|
||||
static void Store32(void *p, uint32 v) {
|
||||
UNALIGNED_STORE32(p, FromHost32(v));
|
||||
}
|
||||
};
|
||||
|
||||
// Some bit-manipulation functions.
|
||||
class Bits {
|
||||
public:
|
||||
// Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0.
|
||||
static int Log2Floor(uint32 n);
|
||||
|
||||
// Return the first set least / most significant bit, 0-indexed. Returns an
|
||||
// undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except
|
||||
// that it's 0-indexed.
|
||||
static int FindLSBSetNonZero(uint32 n);
|
||||
static int FindLSBSetNonZero64(uint64 n);
|
||||
|
||||
private:
|
||||
SNAPPY_DISALLOW_COPY_AND_ASSIGN(Bits);
|
||||
};
|
||||
|
||||
#ifdef HAVE_BUILTIN_CTZ
|
||||
|
||||
inline int Bits::Log2Floor(uint32 n) {
|
||||
return n == 0 ? -1 : 31 ^ __builtin_clz(n);
|
||||
}
|
||||
|
||||
inline int Bits::FindLSBSetNonZero(uint32 n) {
|
||||
return __builtin_ctz(n);
|
||||
}
|
||||
|
||||
inline int Bits::FindLSBSetNonZero64(uint64 n) {
|
||||
return __builtin_ctzll(n);
|
||||
}
|
||||
|
||||
#else // Portable versions.
|
||||
|
||||
inline int Bits::Log2Floor(uint32 n) {
|
||||
if (n == 0)
|
||||
return -1;
|
||||
int log = 0;
|
||||
uint32 value = n;
|
||||
for (int i = 4; i >= 0; --i) {
|
||||
int shift = (1 << i);
|
||||
uint32 x = value >> shift;
|
||||
if (x != 0) {
|
||||
value = x;
|
||||
log += shift;
|
||||
}
|
||||
}
|
||||
assert(value == 1);
|
||||
return log;
|
||||
}
|
||||
|
||||
inline int Bits::FindLSBSetNonZero(uint32 n) {
|
||||
int rc = 31;
|
||||
for (int i = 4, shift = 1 << 4; i >= 0; --i) {
|
||||
const uint32 x = n << shift;
|
||||
if (x != 0) {
|
||||
n = x;
|
||||
rc -= shift;
|
||||
}
|
||||
shift >>= 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero().
|
||||
inline int Bits::FindLSBSetNonZero64(uint64 n) {
|
||||
const uint32 bottombits = static_cast<uint32>(n);
|
||||
if (bottombits == 0) {
|
||||
// Bottom bits are zero, so scan in top bits
|
||||
return 32 + FindLSBSetNonZero(static_cast<uint32>(n >> 32));
|
||||
} else {
|
||||
return FindLSBSetNonZero(bottombits);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // End portable versions.
|
||||
|
||||
// Variable-length integer encoding.
|
||||
class Varint {
|
||||
public:
|
||||
// Maximum lengths of varint encoding of uint32.
|
||||
static const int kMax32 = 5;
|
||||
|
||||
// Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1].
|
||||
// Never reads a character at or beyond limit. If a valid/terminated varint32
|
||||
// was found in the range, stores it in *OUTPUT and returns a pointer just
|
||||
// past the last byte of the varint32. Else returns NULL. On success,
|
||||
// "result <= limit".
|
||||
static const char* Parse32WithLimit(const char* ptr, const char* limit,
|
||||
uint32* OUTPUT);
|
||||
|
||||
// REQUIRES "ptr" points to a buffer of length sufficient to hold "v".
|
||||
// EFFECTS Encodes "v" into "ptr" and returns a pointer to the
|
||||
// byte just past the last encoded byte.
|
||||
static char* Encode32(char* ptr, uint32 v);
|
||||
|
||||
// EFFECTS Appends the varint representation of "value" to "*s".
|
||||
static void Append32(string* s, uint32 value);
|
||||
};
|
||||
|
||||
inline const char* Varint::Parse32WithLimit(const char* p,
|
||||
const char* l,
|
||||
uint32* OUTPUT) {
|
||||
const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
|
||||
const unsigned char* limit = reinterpret_cast<const unsigned char*>(l);
|
||||
uint32 b, result;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result = b & 127; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 7; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done;
|
||||
return NULL; // Value is too long to be a varint32
|
||||
done:
|
||||
*OUTPUT = result;
|
||||
return reinterpret_cast<const char*>(ptr);
|
||||
}
|
||||
|
||||
inline char* Varint::Encode32(char* sptr, uint32 v) {
|
||||
// Operate on characters as unsigneds
|
||||
unsigned char* ptr = reinterpret_cast<unsigned char*>(sptr);
|
||||
static const int B = 128;
|
||||
if (v < (1<<7)) {
|
||||
*(ptr++) = v;
|
||||
} else if (v < (1<<14)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = v>>7;
|
||||
} else if (v < (1<<21)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = v>>14;
|
||||
} else if (v < (1<<28)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = (v>>14) | B;
|
||||
*(ptr++) = v>>21;
|
||||
} else {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = (v>>14) | B;
|
||||
*(ptr++) = (v>>21) | B;
|
||||
*(ptr++) = v>>28;
|
||||
}
|
||||
return reinterpret_cast<char*>(ptr);
|
||||
}
|
||||
|
||||
// If you know the internal layout of the std::string in use, you can
|
||||
// replace this function with one that resizes the string without
|
||||
// filling the new space with zeros (if applicable) --
|
||||
// it will be non-portable but faster.
|
||||
inline void STLStringResizeUninitialized(string* s, size_t new_size) {
|
||||
s->resize(new_size);
|
||||
}
|
||||
|
||||
// Return a mutable char* pointing to a string's internal buffer,
|
||||
// which may not be null-terminated. Writing through this pointer will
|
||||
// modify the string.
|
||||
//
|
||||
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
|
||||
// next call to a string method that invalidates iterators.
|
||||
//
|
||||
// As of 2006-04, there is no standard-blessed way of getting a
|
||||
// mutable reference to a string's internal buffer. However, issue 530
|
||||
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530)
|
||||
// proposes this as the method. It will officially be part of the standard
|
||||
// for C++0x. This should already work on all current implementations.
|
||||
inline char* string_as_array(string* str) {
|
||||
return str->empty() ? NULL : &*str->begin();
|
||||
}
|
||||
|
||||
} // namespace snappy
|
||||
|
||||
#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Various stubs for the open-source version of Snappy.
|
||||
|
||||
#ifndef UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_
|
||||
#define UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "tier0/platform.h"
|
||||
|
||||
// don't use iostream, this make us fail to run under OS X 10.5
|
||||
//#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_SYS_MMAN
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
// Enable 64-bit optimized versions of some routines.
|
||||
#define ARCH_K8 1
|
||||
|
||||
#endif
|
||||
|
||||
// Needed by OS X, among others.
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
// Pull in std::min, std::ostream, and the likes. This is safe because this
|
||||
// header file is never used from any public header files.
|
||||
using namespace std;
|
||||
|
||||
// We only define ARRAYSIZE if it isn't already defined, because this definition
|
||||
// is not very good.
|
||||
#ifndef ARRAYSIZE
|
||||
// The size of an array, if known at compile-time.
|
||||
// Will give unexpected results if used on a pointer.
|
||||
#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||
#endif
|
||||
|
||||
// Static prediction hints.
|
||||
#ifdef HAVE_BUILTIN_EXPECT
|
||||
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||||
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||||
#else
|
||||
#define PREDICT_FALSE(x) x
|
||||
#define PREDICT_TRUE(x) x
|
||||
#endif
|
||||
|
||||
// This is only used for recomputing the tag byte table used during
|
||||
// decompression; for simplicity we just remove it from the open-source
|
||||
// version (anyone who wants to regenerate it can just do the call
|
||||
// themselves within main()).
|
||||
#define DEFINE_bool(flag_name, default_value, description) \
|
||||
bool FLAGS_ ## flag_name = default_value;
|
||||
#define DECLARE_bool(flag_name) \
|
||||
extern bool FLAGS_ ## flag_name;
|
||||
#define REGISTER_MODULE_INITIALIZER(name, code)
|
||||
|
||||
#define SNAPPY_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
namespace snappy {
|
||||
|
||||
static const uint32 kuint32max = static_cast<uint32>(0xFFFFFFFF);
|
||||
static const int64 kint64max = static_cast<int64>(0x7FFFFFFFFFFFFFFFLL);
|
||||
|
||||
// Logging.
|
||||
|
||||
#define LOG(level) LogMessage()
|
||||
#define VLOG(level) true ? (void)0 : \
|
||||
snappy::LogMessageVoidify() & snappy::LogMessage()
|
||||
|
||||
class LogMessage {
|
||||
public:
|
||||
LogMessage() { }
|
||||
~LogMessage() {
|
||||
fprintf( stderr, "\n" );
|
||||
//cerr << endl;
|
||||
}
|
||||
|
||||
LogMessage& operator<<(const std::string& msg) {
|
||||
//cerr << msg;
|
||||
fprintf( stderr, "%s", msg.c_str() );
|
||||
|
||||
return *this;
|
||||
}
|
||||
LogMessage& operator<<(int x) {
|
||||
fprintf( stderr, "%d", x );
|
||||
//cerr << x;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// Asserts, both versions activated in debug mode only,
|
||||
// and ones that are always active.
|
||||
|
||||
#define CRASH_UNLESS(condition) \
|
||||
PREDICT_TRUE(condition) ? (void)0 : \
|
||||
snappy::LogMessageVoidify() & snappy::LogMessageCrash()
|
||||
|
||||
class LogMessageCrash : public LogMessage {
|
||||
public:
|
||||
LogMessageCrash() { }
|
||||
#if _MSC_VER == 1700
|
||||
// Bogus warning from VS 2012:
|
||||
// warning C4722: 'snappy::LogMessageCrash::~LogMessageCrash' : destructor never returns, potential memory leak
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4722)
|
||||
#endif
|
||||
~LogMessageCrash() {
|
||||
fprintf( stderr, "\n" );
|
||||
// cerr << endl;
|
||||
abort();
|
||||
}
|
||||
};
|
||||
#if _MSC_VER == 1700
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// This class is used to explicitly ignore values in the conditional
|
||||
// logging macros. This avoids compiler warnings like "value computed
|
||||
// is not used" and "statement has no effect".
|
||||
|
||||
class LogMessageVoidify {
|
||||
public:
|
||||
LogMessageVoidify() { }
|
||||
// This has to be an operator with a precedence lower than << but
|
||||
// higher than ?:
|
||||
void operator&(const LogMessage&) { }
|
||||
};
|
||||
|
||||
#define CHECK(cond) CRASH_UNLESS(cond)
|
||||
#define CHECK_LE(a, b) CRASH_UNLESS((a) <= (b))
|
||||
#define CHECK_GE(a, b) CRASH_UNLESS((a) >= (b))
|
||||
#define CHECK_EQ(a, b) CRASH_UNLESS((a) == (b))
|
||||
#define CHECK_NE(a, b) CRASH_UNLESS((a) != (b))
|
||||
#define CHECK_LT(a, b) CRASH_UNLESS((a) < (b))
|
||||
#define CHECK_GT(a, b) CRASH_UNLESS((a) > (b))
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#define DCHECK(cond) CRASH_UNLESS(true)
|
||||
#define DCHECK_LE(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_GE(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_EQ(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_NE(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_LT(a, b) CRASH_UNLESS(true)
|
||||
#define DCHECK_GT(a, b) CRASH_UNLESS(true)
|
||||
|
||||
#else
|
||||
|
||||
#define DCHECK(cond) CHECK(cond)
|
||||
#define DCHECK_LE(a, b) CHECK_LE(a, b)
|
||||
#define DCHECK_GE(a, b) CHECK_GE(a, b)
|
||||
#define DCHECK_EQ(a, b) CHECK_EQ(a, b)
|
||||
#define DCHECK_NE(a, b) CHECK_NE(a, b)
|
||||
#define DCHECK_LT(a, b) CHECK_LT(a, b)
|
||||
#define DCHECK_GT(a, b) CHECK_GT(a, b)
|
||||
|
||||
#endif
|
||||
|
||||
// Potentially unaligned loads and stores.
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
|
||||
|
||||
#define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
|
||||
#define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
|
||||
#define UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
|
||||
|
||||
#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_val))
|
||||
#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_val))
|
||||
#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_val))
|
||||
|
||||
#else
|
||||
|
||||
// These functions are provided for architectures that don't support
|
||||
// unaligned loads and stores.
|
||||
|
||||
inline uint16 UNALIGNED_LOAD16(const void *p) {
|
||||
uint16 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint32 UNALIGNED_LOAD32(const void *p) {
|
||||
uint32 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint64 UNALIGNED_LOAD64(const void *p) {
|
||||
uint64 t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline void UNALIGNED_STORE16(void *p, uint16 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void UNALIGNED_STORE32(void *p, uint32 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void UNALIGNED_STORE64(void *p, uint64 v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// The following guarantees declaration of the byte swap functions.
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h>
|
||||
#define bswap_16(x) _byteswap_ushort(x)
|
||||
#define bswap_32(x) _byteswap_ulong(x)
|
||||
#define bswap_64(x) _byteswap_uint64(x)
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// Mac OS X / Darwin features
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16(x) OSSwapInt16(x)
|
||||
#define bswap_32(x) OSSwapInt32(x)
|
||||
#define bswap_64(x) OSSwapInt64(x)
|
||||
|
||||
#else
|
||||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#endif // WORDS_BIGENDIAN
|
||||
|
||||
// Convert to little-endian storage, opposite of network format.
|
||||
// Convert x from host to little endian: x = LittleEndian.FromHost(x);
|
||||
// convert x from little endian to host: x = LittleEndian.ToHost(x);
|
||||
//
|
||||
// Store values into unaligned memory converting to little endian order:
|
||||
// LittleEndian.Store16(p, x);
|
||||
//
|
||||
// Load unaligned values stored in little endian converting to host order:
|
||||
// x = LittleEndian.Load16(p);
|
||||
class LittleEndian {
|
||||
public:
|
||||
// Conversion functions.
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
static uint16 FromHost16(uint16 x) { return bswap_16(x); }
|
||||
static uint16 ToHost16(uint16 x) { return bswap_16(x); }
|
||||
|
||||
static uint32 FromHost32(uint32 x) { return bswap_32(x); }
|
||||
static uint32 ToHost32(uint32 x) { return bswap_32(x); }
|
||||
|
||||
static bool IsLittleEndian() { return false; }
|
||||
|
||||
#else // !defined(WORDS_BIGENDIAN)
|
||||
|
||||
static uint16 FromHost16(uint16 x) { return x; }
|
||||
static uint16 ToHost16(uint16 x) { return x; }
|
||||
|
||||
static uint32 FromHost32(uint32 x) { return x; }
|
||||
static uint32 ToHost32(uint32 x) { return x; }
|
||||
|
||||
static bool IsLittleEndian() { return true; }
|
||||
|
||||
#endif // !defined(WORDS_BIGENDIAN)
|
||||
|
||||
// Functions to do unaligned loads and stores in little-endian order.
|
||||
static uint16 Load16(const void *p) {
|
||||
return ToHost16(UNALIGNED_LOAD16(p));
|
||||
}
|
||||
|
||||
static void Store16(void *p, uint16 v) {
|
||||
UNALIGNED_STORE16(p, FromHost16(v));
|
||||
}
|
||||
|
||||
static uint32 Load32(const void *p) {
|
||||
return ToHost32(UNALIGNED_LOAD32(p));
|
||||
}
|
||||
|
||||
static void Store32(void *p, uint32 v) {
|
||||
UNALIGNED_STORE32(p, FromHost32(v));
|
||||
}
|
||||
};
|
||||
|
||||
// Some bit-manipulation functions.
|
||||
class Bits {
|
||||
public:
|
||||
// Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0.
|
||||
static int Log2Floor(uint32 n);
|
||||
|
||||
// Return the first set least / most significant bit, 0-indexed. Returns an
|
||||
// undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except
|
||||
// that it's 0-indexed.
|
||||
static int FindLSBSetNonZero(uint32 n);
|
||||
static int FindLSBSetNonZero64(uint64 n);
|
||||
|
||||
private:
|
||||
SNAPPY_DISALLOW_COPY_AND_ASSIGN(Bits);
|
||||
};
|
||||
|
||||
#ifdef HAVE_BUILTIN_CTZ
|
||||
|
||||
inline int Bits::Log2Floor(uint32 n) {
|
||||
return n == 0 ? -1 : 31 ^ __builtin_clz(n);
|
||||
}
|
||||
|
||||
inline int Bits::FindLSBSetNonZero(uint32 n) {
|
||||
return __builtin_ctz(n);
|
||||
}
|
||||
|
||||
inline int Bits::FindLSBSetNonZero64(uint64 n) {
|
||||
return __builtin_ctzll(n);
|
||||
}
|
||||
|
||||
#else // Portable versions.
|
||||
|
||||
inline int Bits::Log2Floor(uint32 n) {
|
||||
if (n == 0)
|
||||
return -1;
|
||||
int log = 0;
|
||||
uint32 value = n;
|
||||
for (int i = 4; i >= 0; --i) {
|
||||
int shift = (1 << i);
|
||||
uint32 x = value >> shift;
|
||||
if (x != 0) {
|
||||
value = x;
|
||||
log += shift;
|
||||
}
|
||||
}
|
||||
assert(value == 1);
|
||||
return log;
|
||||
}
|
||||
|
||||
inline int Bits::FindLSBSetNonZero(uint32 n) {
|
||||
int rc = 31;
|
||||
for (int i = 4, shift = 1 << 4; i >= 0; --i) {
|
||||
const uint32 x = n << shift;
|
||||
if (x != 0) {
|
||||
n = x;
|
||||
rc -= shift;
|
||||
}
|
||||
shift >>= 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero().
|
||||
inline int Bits::FindLSBSetNonZero64(uint64 n) {
|
||||
const uint32 bottombits = static_cast<uint32>(n);
|
||||
if (bottombits == 0) {
|
||||
// Bottom bits are zero, so scan in top bits
|
||||
return 32 + FindLSBSetNonZero(static_cast<uint32>(n >> 32));
|
||||
} else {
|
||||
return FindLSBSetNonZero(bottombits);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // End portable versions.
|
||||
|
||||
// Variable-length integer encoding.
|
||||
class Varint {
|
||||
public:
|
||||
// Maximum lengths of varint encoding of uint32.
|
||||
static const int kMax32 = 5;
|
||||
|
||||
// Attempts to parse a varint32 from a prefix of the bytes in [ptr,limit-1].
|
||||
// Never reads a character at or beyond limit. If a valid/terminated varint32
|
||||
// was found in the range, stores it in *OUTPUT and returns a pointer just
|
||||
// past the last byte of the varint32. Else returns NULL. On success,
|
||||
// "result <= limit".
|
||||
static const char* Parse32WithLimit(const char* ptr, const char* limit,
|
||||
uint32* OUTPUT);
|
||||
|
||||
// REQUIRES "ptr" points to a buffer of length sufficient to hold "v".
|
||||
// EFFECTS Encodes "v" into "ptr" and returns a pointer to the
|
||||
// byte just past the last encoded byte.
|
||||
static char* Encode32(char* ptr, uint32 v);
|
||||
|
||||
// EFFECTS Appends the varint representation of "value" to "*s".
|
||||
static void Append32(string* s, uint32 value);
|
||||
};
|
||||
|
||||
inline const char* Varint::Parse32WithLimit(const char* p,
|
||||
const char* l,
|
||||
uint32* OUTPUT) {
|
||||
const unsigned char* ptr = reinterpret_cast<const unsigned char*>(p);
|
||||
const unsigned char* limit = reinterpret_cast<const unsigned char*>(l);
|
||||
uint32 b, result;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result = b & 127; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 7; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 14; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 21; if (b < 128) goto done;
|
||||
if (ptr >= limit) return NULL;
|
||||
b = *(ptr++); result |= (b & 127) << 28; if (b < 16) goto done;
|
||||
return NULL; // Value is too long to be a varint32
|
||||
done:
|
||||
*OUTPUT = result;
|
||||
return reinterpret_cast<const char*>(ptr);
|
||||
}
|
||||
|
||||
inline char* Varint::Encode32(char* sptr, uint32 v) {
|
||||
// Operate on characters as unsigneds
|
||||
unsigned char* ptr = reinterpret_cast<unsigned char*>(sptr);
|
||||
static const int B = 128;
|
||||
if (v < (1<<7)) {
|
||||
*(ptr++) = v;
|
||||
} else if (v < (1<<14)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = v>>7;
|
||||
} else if (v < (1<<21)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = v>>14;
|
||||
} else if (v < (1<<28)) {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = (v>>14) | B;
|
||||
*(ptr++) = v>>21;
|
||||
} else {
|
||||
*(ptr++) = v | B;
|
||||
*(ptr++) = (v>>7) | B;
|
||||
*(ptr++) = (v>>14) | B;
|
||||
*(ptr++) = (v>>21) | B;
|
||||
*(ptr++) = v>>28;
|
||||
}
|
||||
return reinterpret_cast<char*>(ptr);
|
||||
}
|
||||
|
||||
// If you know the internal layout of the std::string in use, you can
|
||||
// replace this function with one that resizes the string without
|
||||
// filling the new space with zeros (if applicable) --
|
||||
// it will be non-portable but faster.
|
||||
inline void STLStringResizeUninitialized(string* s, size_t new_size) {
|
||||
s->resize(new_size);
|
||||
}
|
||||
|
||||
// Return a mutable char* pointing to a string's internal buffer,
|
||||
// which may not be null-terminated. Writing through this pointer will
|
||||
// modify the string.
|
||||
//
|
||||
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
|
||||
// next call to a string method that invalidates iterators.
|
||||
//
|
||||
// As of 2006-04, there is no standard-blessed way of getting a
|
||||
// mutable reference to a string's internal buffer. However, issue 530
|
||||
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530)
|
||||
// proposes this as the method. It will officially be part of the standard
|
||||
// for C++0x. This should already work on all current implementations.
|
||||
inline char* string_as_array(string* str) {
|
||||
return str->empty() ? NULL : &*str->begin();
|
||||
}
|
||||
|
||||
} // namespace snappy
|
||||
|
||||
#endif // UTIL_SNAPPY_OPENSOURCE_SNAPPY_STUBS_INTERNAL_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,141 +1,141 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier1/sparsematrix.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
void CSparseMatrix::AdjustAllRowIndicesAfter( int nStartRow, int nDelta )
|
||||
{
|
||||
// now, we need to offset the starting position of all subsequent rows by -1 to compensate for the removal of this element
|
||||
for( int nOtherRow = nStartRow + 1 ; nOtherRow < Height(); nOtherRow++ )
|
||||
{
|
||||
m_rowDescriptors[nOtherRow].m_nDataIndex += nDelta;
|
||||
}
|
||||
}
|
||||
|
||||
void CSparseMatrix::SetDimensions( int nNumRows, int nNumCols )
|
||||
{
|
||||
m_nNumRows = nNumRows;
|
||||
m_nNumCols = nNumCols;
|
||||
m_entries.SetCount( 0 );
|
||||
m_rowDescriptors.SetCount( m_nNumRows );
|
||||
// and set all rows to be empty
|
||||
for( int i = 0; i < m_nNumRows; i++ )
|
||||
{
|
||||
m_rowDescriptors[i].m_nNonZeroCount = 0;
|
||||
m_rowDescriptors[i].m_nDataIndex = 0;
|
||||
}
|
||||
m_nHighestRowAppendedTo = -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CSparseMatrix::SetElement( int nRow, int nCol, float flValue )
|
||||
{
|
||||
Assert( nCol < m_nNumCols );
|
||||
int nCount = m_rowDescriptors[nRow].m_nNonZeroCount;
|
||||
bool bValueIsZero = ( flValue == 0.0 );
|
||||
int nFirstEntryIndex = m_rowDescriptors[nRow].m_nDataIndex;
|
||||
if ( nCount )
|
||||
{
|
||||
NonZeroValueDescriptor_t *pValue = &( m_entries[nFirstEntryIndex] );
|
||||
int i;
|
||||
for( i = 0; i < nCount; i++ )
|
||||
{
|
||||
int nIdx = pValue->m_nColumnNumber;
|
||||
if ( nIdx == nCol ) // we found it!
|
||||
{
|
||||
if ( !bValueIsZero )
|
||||
{
|
||||
// we want to overwrite the existing value
|
||||
pValue->m_flValue = flValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is a non-zero element currently at this position. We need to remove it
|
||||
// and we need to remove its storage.
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount--;
|
||||
m_entries.Remove( nFirstEntryIndex + i );
|
||||
// now, we need to offset the starting position of all subsequent rows by -1 to compensate for the removal of this element
|
||||
AdjustAllRowIndicesAfter( nRow, -1 );
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( nIdx > nCol )
|
||||
{
|
||||
break;
|
||||
}
|
||||
pValue++;
|
||||
}
|
||||
// we did not find an entry for this cell. If we were writing zero, fine - we are
|
||||
// done, otherwise insert
|
||||
if (! bValueIsZero )
|
||||
{
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount++;
|
||||
NonZeroValueDescriptor_t newValue;
|
||||
newValue.m_nColumnNumber = nCol;
|
||||
newValue.m_flValue = flValue;
|
||||
if ( i == nCount ) // need to append
|
||||
{
|
||||
m_entries.InsertAfter( nFirstEntryIndex + nCount - 1, newValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entries.InsertBefore( nFirstEntryIndex + i, newValue );
|
||||
}
|
||||
// now, we need to offset the starting position of all subsequent rows by -1 to compensate for the addition of this element
|
||||
AdjustAllRowIndicesAfter( nRow, +1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// row is empty. We may need to insert
|
||||
if ( ! bValueIsZero )
|
||||
{
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount++;
|
||||
NonZeroValueDescriptor_t newValue;
|
||||
newValue.m_nColumnNumber = nCol;
|
||||
newValue.m_flValue = flValue;
|
||||
m_entries.InsertBefore( nFirstEntryIndex, newValue );
|
||||
AdjustAllRowIndicesAfter( nRow, +1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSparseMatrix::FinishedAppending( void )
|
||||
{
|
||||
// set all pointers to space for subsequent rows to the right value
|
||||
for( int i = m_nHighestRowAppendedTo + 1 ; i < Height(); i++ )
|
||||
{
|
||||
m_rowDescriptors[i].m_nDataIndex = m_entries.Count();
|
||||
}
|
||||
}
|
||||
|
||||
void CSparseMatrix::AppendElement( int nRow, int nColumn, float flValue )
|
||||
{
|
||||
if ( flValue != 0.0 )
|
||||
{
|
||||
if ( m_nHighestRowAppendedTo != nRow )
|
||||
{
|
||||
Assert( nRow > m_nHighestRowAppendedTo );
|
||||
for( int i = m_nHighestRowAppendedTo + 1; i <= nRow; i++ )
|
||||
{
|
||||
m_rowDescriptors[i].m_nDataIndex = m_entries.Count();
|
||||
}
|
||||
}
|
||||
m_nHighestRowAppendedTo = nRow;
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount++;
|
||||
NonZeroValueDescriptor_t newDesc;
|
||||
newDesc.m_nColumnNumber = nColumn;
|
||||
newDesc.m_flValue = flValue;
|
||||
m_entries.AddToTail( newDesc );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier1/sparsematrix.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
void CSparseMatrix::AdjustAllRowIndicesAfter( int nStartRow, int nDelta )
|
||||
{
|
||||
// now, we need to offset the starting position of all subsequent rows by -1 to compensate for the removal of this element
|
||||
for( int nOtherRow = nStartRow + 1 ; nOtherRow < Height(); nOtherRow++ )
|
||||
{
|
||||
m_rowDescriptors[nOtherRow].m_nDataIndex += nDelta;
|
||||
}
|
||||
}
|
||||
|
||||
void CSparseMatrix::SetDimensions( int nNumRows, int nNumCols )
|
||||
{
|
||||
m_nNumRows = nNumRows;
|
||||
m_nNumCols = nNumCols;
|
||||
m_entries.SetCount( 0 );
|
||||
m_rowDescriptors.SetCount( m_nNumRows );
|
||||
// and set all rows to be empty
|
||||
for( int i = 0; i < m_nNumRows; i++ )
|
||||
{
|
||||
m_rowDescriptors[i].m_nNonZeroCount = 0;
|
||||
m_rowDescriptors[i].m_nDataIndex = 0;
|
||||
}
|
||||
m_nHighestRowAppendedTo = -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CSparseMatrix::SetElement( int nRow, int nCol, float flValue )
|
||||
{
|
||||
Assert( nCol < m_nNumCols );
|
||||
int nCount = m_rowDescriptors[nRow].m_nNonZeroCount;
|
||||
bool bValueIsZero = ( flValue == 0.0 );
|
||||
int nFirstEntryIndex = m_rowDescriptors[nRow].m_nDataIndex;
|
||||
if ( nCount )
|
||||
{
|
||||
NonZeroValueDescriptor_t *pValue = &( m_entries[nFirstEntryIndex] );
|
||||
int i;
|
||||
for( i = 0; i < nCount; i++ )
|
||||
{
|
||||
int nIdx = pValue->m_nColumnNumber;
|
||||
if ( nIdx == nCol ) // we found it!
|
||||
{
|
||||
if ( !bValueIsZero )
|
||||
{
|
||||
// we want to overwrite the existing value
|
||||
pValue->m_flValue = flValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is a non-zero element currently at this position. We need to remove it
|
||||
// and we need to remove its storage.
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount--;
|
||||
m_entries.Remove( nFirstEntryIndex + i );
|
||||
// now, we need to offset the starting position of all subsequent rows by -1 to compensate for the removal of this element
|
||||
AdjustAllRowIndicesAfter( nRow, -1 );
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( nIdx > nCol )
|
||||
{
|
||||
break;
|
||||
}
|
||||
pValue++;
|
||||
}
|
||||
// we did not find an entry for this cell. If we were writing zero, fine - we are
|
||||
// done, otherwise insert
|
||||
if (! bValueIsZero )
|
||||
{
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount++;
|
||||
NonZeroValueDescriptor_t newValue;
|
||||
newValue.m_nColumnNumber = nCol;
|
||||
newValue.m_flValue = flValue;
|
||||
if ( i == nCount ) // need to append
|
||||
{
|
||||
m_entries.InsertAfter( nFirstEntryIndex + nCount - 1, newValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entries.InsertBefore( nFirstEntryIndex + i, newValue );
|
||||
}
|
||||
// now, we need to offset the starting position of all subsequent rows by -1 to compensate for the addition of this element
|
||||
AdjustAllRowIndicesAfter( nRow, +1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// row is empty. We may need to insert
|
||||
if ( ! bValueIsZero )
|
||||
{
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount++;
|
||||
NonZeroValueDescriptor_t newValue;
|
||||
newValue.m_nColumnNumber = nCol;
|
||||
newValue.m_flValue = flValue;
|
||||
m_entries.InsertBefore( nFirstEntryIndex, newValue );
|
||||
AdjustAllRowIndicesAfter( nRow, +1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSparseMatrix::FinishedAppending( void )
|
||||
{
|
||||
// set all pointers to space for subsequent rows to the right value
|
||||
for( int i = m_nHighestRowAppendedTo + 1 ; i < Height(); i++ )
|
||||
{
|
||||
m_rowDescriptors[i].m_nDataIndex = m_entries.Count();
|
||||
}
|
||||
}
|
||||
|
||||
void CSparseMatrix::AppendElement( int nRow, int nColumn, float flValue )
|
||||
{
|
||||
if ( flValue != 0.0 )
|
||||
{
|
||||
if ( m_nHighestRowAppendedTo != nRow )
|
||||
{
|
||||
Assert( nRow > m_nHighestRowAppendedTo );
|
||||
for( int i = m_nHighestRowAppendedTo + 1; i <= nRow; i++ )
|
||||
{
|
||||
m_rowDescriptors[i].m_nDataIndex = m_entries.Count();
|
||||
}
|
||||
}
|
||||
m_nHighestRowAppendedTo = nRow;
|
||||
m_rowDescriptors[nRow].m_nNonZeroCount++;
|
||||
NonZeroValueDescriptor_t newDesc;
|
||||
newDesc.m_nColumnNumber = nColumn;
|
||||
newDesc.m_flValue = flValue;
|
||||
m_entries.AddToTail( newDesc );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
#include "strtools.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
CSplitString::CSplitString(const char *pString, const char **pSeparators, int nSeparators)
|
||||
{
|
||||
Construct(pString, pSeparators, nSeparators);
|
||||
};
|
||||
|
||||
CSplitString::CSplitString( const char *pString, const char *pSeparator)
|
||||
{
|
||||
Construct( pString, &pSeparator, 1 );
|
||||
}
|
||||
|
||||
CSplitString::~CSplitString()
|
||||
{
|
||||
if(m_szBuffer)
|
||||
delete [] m_szBuffer;
|
||||
}
|
||||
|
||||
void CSplitString::Construct( const char *pString, const char **pSeparators, int nSeparators )
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// make a duplicate of the original string. We'll use pieces of this duplicate to tokenize the string
|
||||
// and create NULL-terminated tokens of the original string
|
||||
//
|
||||
int nOriginalStringLength = V_strlen(pString);
|
||||
m_szBuffer = new char[nOriginalStringLength + 1];
|
||||
memcpy(m_szBuffer, pString, nOriginalStringLength + 1);
|
||||
|
||||
this->Purge();
|
||||
const char *pCurPos = pString;
|
||||
while ( 1 )
|
||||
{
|
||||
int iFirstSeparator = -1;
|
||||
const char *pFirstSeparator = 0;
|
||||
for ( int i=0; i < nSeparators; i++ )
|
||||
{
|
||||
const char *pTest = V_stristr( pCurPos, pSeparators[i] );
|
||||
if ( pTest && (!pFirstSeparator || pTest < pFirstSeparator) )
|
||||
{
|
||||
iFirstSeparator = i;
|
||||
pFirstSeparator = pTest;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pFirstSeparator )
|
||||
{
|
||||
// Split on this separator and continue on.
|
||||
int separatorLen = strlen( pSeparators[iFirstSeparator] );
|
||||
if ( pFirstSeparator > pCurPos )
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// Cut the token out of the duplicate string
|
||||
char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString);
|
||||
int nTokenLength = pFirstSeparator-pCurPos;
|
||||
Assert(nTokenLength > 0 && !memcmp(pTokenInDuplicate,pCurPos,nTokenLength));
|
||||
pTokenInDuplicate[nTokenLength] = '\0';
|
||||
|
||||
this->AddToTail( pTokenInDuplicate /*AllocString( pCurPos, pFirstSeparator-pCurPos )*/ );
|
||||
}
|
||||
|
||||
pCurPos = pFirstSeparator + separatorLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the rest of the string
|
||||
if ( int nTokenLength = strlen( pCurPos ) )
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// There's no need to cut this token, because there's no separator after it.
|
||||
// just add its copy in the buffer to the tail
|
||||
char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString);
|
||||
Assert(!memcmp(pTokenInDuplicate, pCurPos, nTokenLength));
|
||||
|
||||
this->AddToTail( pTokenInDuplicate/*AllocString( pCurPos, -1 )*/ );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSplitString::PurgeAndDeleteElements()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
#include "strtools.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
CSplitString::CSplitString(const char *pString, const char **pSeparators, int nSeparators)
|
||||
{
|
||||
Construct(pString, pSeparators, nSeparators);
|
||||
};
|
||||
|
||||
CSplitString::CSplitString( const char *pString, const char *pSeparator)
|
||||
{
|
||||
Construct( pString, &pSeparator, 1 );
|
||||
}
|
||||
|
||||
CSplitString::~CSplitString()
|
||||
{
|
||||
if(m_szBuffer)
|
||||
delete [] m_szBuffer;
|
||||
}
|
||||
|
||||
void CSplitString::Construct( const char *pString, const char **pSeparators, int nSeparators )
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// make a duplicate of the original string. We'll use pieces of this duplicate to tokenize the string
|
||||
// and create NULL-terminated tokens of the original string
|
||||
//
|
||||
int nOriginalStringLength = V_strlen(pString);
|
||||
m_szBuffer = new char[nOriginalStringLength + 1];
|
||||
memcpy(m_szBuffer, pString, nOriginalStringLength + 1);
|
||||
|
||||
this->Purge();
|
||||
const char *pCurPos = pString;
|
||||
while ( 1 )
|
||||
{
|
||||
int iFirstSeparator = -1;
|
||||
const char *pFirstSeparator = 0;
|
||||
for ( int i=0; i < nSeparators; i++ )
|
||||
{
|
||||
const char *pTest = V_stristr( pCurPos, pSeparators[i] );
|
||||
if ( pTest && (!pFirstSeparator || pTest < pFirstSeparator) )
|
||||
{
|
||||
iFirstSeparator = i;
|
||||
pFirstSeparator = pTest;
|
||||
}
|
||||
}
|
||||
|
||||
if ( pFirstSeparator )
|
||||
{
|
||||
// Split on this separator and continue on.
|
||||
int separatorLen = strlen( pSeparators[iFirstSeparator] );
|
||||
if ( pFirstSeparator > pCurPos )
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// Cut the token out of the duplicate string
|
||||
char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString);
|
||||
int nTokenLength = pFirstSeparator-pCurPos;
|
||||
Assert(nTokenLength > 0 && !memcmp(pTokenInDuplicate,pCurPos,nTokenLength));
|
||||
pTokenInDuplicate[nTokenLength] = '\0';
|
||||
|
||||
this->AddToTail( pTokenInDuplicate /*AllocString( pCurPos, pFirstSeparator-pCurPos )*/ );
|
||||
}
|
||||
|
||||
pCurPos = pFirstSeparator + separatorLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the rest of the string
|
||||
if ( int nTokenLength = strlen( pCurPos ) )
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// There's no need to cut this token, because there's no separator after it.
|
||||
// just add its copy in the buffer to the tail
|
||||
char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString);
|
||||
Assert(!memcmp(pTokenInDuplicate, pCurPos, nTokenLength));
|
||||
|
||||
this->AddToTail( pTokenInDuplicate/*AllocString( pCurPos, -1 )*/ );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSplitString::PurgeAndDeleteElements()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
|
||||
@@ -1,334 +1,334 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "convar.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "stringpool.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "generichash.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for string sorted associative data structures
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool StrLess( const char * const &pszLeft, const char * const &pszRight )
|
||||
{
|
||||
return ( Q_stricmp( pszLeft, pszRight) < 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CStringPool::CStringPool()
|
||||
: m_Strings( 32, 256, StrLess )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CStringPool::~CStringPool()
|
||||
{
|
||||
FreeAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
unsigned int CStringPool::Count() const
|
||||
{
|
||||
return m_Strings.Count();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
const char * CStringPool::Find( const char *pszValue )
|
||||
{
|
||||
unsigned short i = m_Strings.Find(pszValue);
|
||||
if ( m_Strings.IsValidIndex(i) )
|
||||
return m_Strings[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * CStringPool::Allocate( const char *pszValue )
|
||||
{
|
||||
char *pszNew;
|
||||
|
||||
unsigned short i = m_Strings.Find(pszValue);
|
||||
bool bNew = (i == m_Strings.InvalidIndex());
|
||||
|
||||
if ( !bNew )
|
||||
return m_Strings[i];
|
||||
|
||||
pszNew = strdup( pszValue );
|
||||
|
||||
if ( bNew )
|
||||
m_Strings.Insert( pszNew );
|
||||
|
||||
return pszNew;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CStringPool::FreeAll()
|
||||
{
|
||||
unsigned short i = m_Strings.FirstInorder();
|
||||
while ( i != m_Strings.InvalidIndex() )
|
||||
{
|
||||
free( (void *)m_Strings[i] );
|
||||
i = m_Strings.NextInorder(i);
|
||||
}
|
||||
m_Strings.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
CCountedStringPool::CCountedStringPool()
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
m_HashTable.EnsureCount(HASH_TABLE_SIZE);
|
||||
|
||||
for( int i = 0; i < m_HashTable.Count(); i++ )
|
||||
{
|
||||
m_HashTable[i] = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
m_FreeListStart = INVALID_ELEMENT;
|
||||
m_Elements.AddToTail();
|
||||
m_Elements[0].pString = NULL;
|
||||
m_Elements[0].nReferenceCount = 0;
|
||||
m_Elements[0].nNextElement = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
CCountedStringPool::~CCountedStringPool()
|
||||
{
|
||||
FreeAll();
|
||||
}
|
||||
|
||||
void CCountedStringPool::FreeAll()
|
||||
{
|
||||
int i;
|
||||
|
||||
// Reset the hash table:
|
||||
for( i = 0; i < m_HashTable.Count(); i++ )
|
||||
{
|
||||
m_HashTable[i] = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
// Blow away the free list:
|
||||
m_FreeListStart = INVALID_ELEMENT;
|
||||
|
||||
for( i = 0; i < m_Elements.Count(); i++ )
|
||||
{
|
||||
if( m_Elements[i].pString )
|
||||
{
|
||||
delete [] m_Elements[i].pString;
|
||||
m_Elements[i].pString = NULL;
|
||||
m_Elements[i].nReferenceCount = 0;
|
||||
m_Elements[i].nNextElement = INVALID_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all but the invalid element:
|
||||
m_Elements.RemoveAll();
|
||||
m_Elements.AddToTail();
|
||||
m_Elements[0].pString = NULL;
|
||||
m_Elements[0].nReferenceCount = 0;
|
||||
m_Elements[0].nNextElement = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
|
||||
unsigned short CCountedStringPool::FindStringHandle( const char* pIntrinsic )
|
||||
{
|
||||
if( pIntrinsic == NULL )
|
||||
return INVALID_ELEMENT;
|
||||
|
||||
unsigned short nHashBucketIndex = (HashStringCaseless(pIntrinsic ) %HASH_TABLE_SIZE);
|
||||
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
|
||||
|
||||
// Does the bucket already exist?
|
||||
if( nCurrentBucket != INVALID_ELEMENT )
|
||||
{
|
||||
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
|
||||
{
|
||||
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
|
||||
{
|
||||
return nCurrentBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
char* CCountedStringPool::FindString( const char* pIntrinsic )
|
||||
{
|
||||
if( pIntrinsic == NULL )
|
||||
return NULL;
|
||||
|
||||
// Yes, this will be NULL on failure.
|
||||
return m_Elements[FindStringHandle(pIntrinsic)].pString;
|
||||
}
|
||||
|
||||
unsigned short CCountedStringPool::ReferenceStringHandle( const char* pIntrinsic )
|
||||
{
|
||||
if( pIntrinsic == NULL )
|
||||
return INVALID_ELEMENT;
|
||||
|
||||
unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % HASH_TABLE_SIZE);
|
||||
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
|
||||
|
||||
// Does the bucket already exist?
|
||||
if( nCurrentBucket != INVALID_ELEMENT )
|
||||
{
|
||||
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
|
||||
{
|
||||
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
|
||||
{
|
||||
// Anyone who hits 65k references is permanant
|
||||
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
|
||||
{
|
||||
m_Elements[nCurrentBucket].nReferenceCount ++ ;
|
||||
}
|
||||
return nCurrentBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_FreeListStart != INVALID_ELEMENT )
|
||||
{
|
||||
nCurrentBucket = m_FreeListStart;
|
||||
m_FreeListStart = m_Elements[nCurrentBucket].nNextElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCurrentBucket = m_Elements.AddToTail();
|
||||
}
|
||||
|
||||
m_Elements[nCurrentBucket].nReferenceCount = 1;
|
||||
|
||||
// Insert at the beginning of the bucket:
|
||||
m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ];
|
||||
m_HashTable[ nHashBucketIndex ] = nCurrentBucket;
|
||||
|
||||
m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1];
|
||||
Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic );
|
||||
|
||||
return nCurrentBucket;
|
||||
}
|
||||
|
||||
|
||||
char* CCountedStringPool::ReferenceString( const char* pIntrinsic )
|
||||
{
|
||||
if(!pIntrinsic)
|
||||
return NULL;
|
||||
|
||||
return m_Elements[ReferenceStringHandle( pIntrinsic)].pString;
|
||||
}
|
||||
|
||||
void CCountedStringPool::DereferenceString( const char* pIntrinsic )
|
||||
{
|
||||
// If we get a NULL pointer, just return
|
||||
if (!pIntrinsic)
|
||||
return;
|
||||
|
||||
unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % m_HashTable.Count());
|
||||
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
|
||||
|
||||
// If there isn't anything in the bucket, just return.
|
||||
if ( nCurrentBucket == INVALID_ELEMENT )
|
||||
return;
|
||||
|
||||
for( unsigned short previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
|
||||
{
|
||||
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
|
||||
{
|
||||
// Anyone who hits 65k references is permanant
|
||||
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
|
||||
{
|
||||
m_Elements[nCurrentBucket].nReferenceCount --;
|
||||
}
|
||||
|
||||
if( m_Elements[nCurrentBucket].nReferenceCount == 0 )
|
||||
{
|
||||
if( previous == INVALID_ELEMENT )
|
||||
{
|
||||
m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement;
|
||||
}
|
||||
|
||||
delete [] m_Elements[nCurrentBucket].pString;
|
||||
m_Elements[nCurrentBucket].pString = NULL;
|
||||
m_Elements[nCurrentBucket].nReferenceCount = 0;
|
||||
|
||||
m_Elements[nCurrentBucket].nNextElement = m_FreeListStart;
|
||||
m_FreeListStart = nCurrentBucket;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
previous = nCurrentBucket;
|
||||
}
|
||||
}
|
||||
|
||||
char* CCountedStringPool::HandleToString( unsigned short handle )
|
||||
{
|
||||
return m_Elements[handle].pString;
|
||||
}
|
||||
|
||||
void CCountedStringPool::SpewStrings()
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < m_Elements.Count(); i++ )
|
||||
{
|
||||
char* string = m_Elements[i].pString;
|
||||
|
||||
Msg("String %d: ref:%d %s", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string);
|
||||
}
|
||||
|
||||
Msg("\n%d total counted strings.", m_Elements.Count());
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
CON_COMMAND( test_stringpool, "Tests the class CStringPool" )
|
||||
{
|
||||
CStringPool pool;
|
||||
|
||||
Assert(pool.Count() == 0);
|
||||
|
||||
pool.Allocate("test");
|
||||
Assert(pool.Count() == 1);
|
||||
|
||||
pool.Allocate("test");
|
||||
Assert(pool.Count() == 1);
|
||||
|
||||
pool.Allocate("test2");
|
||||
Assert(pool.Count() == 2);
|
||||
|
||||
Assert( pool.Find("test2") != NULL );
|
||||
Assert( pool.Find("TEST") != NULL );
|
||||
Assert( pool.Find("Test2") != NULL );
|
||||
Assert( pool.Find("test") != NULL );
|
||||
|
||||
pool.FreeAll();
|
||||
Assert(pool.Count() == 0);
|
||||
|
||||
Msg("Pass.");
|
||||
}
|
||||
#endif
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "convar.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "stringpool.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "generichash.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for string sorted associative data structures
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool StrLess( const char * const &pszLeft, const char * const &pszRight )
|
||||
{
|
||||
return ( Q_stricmp( pszLeft, pszRight) < 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CStringPool::CStringPool()
|
||||
: m_Strings( 32, 256, StrLess )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CStringPool::~CStringPool()
|
||||
{
|
||||
FreeAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
unsigned int CStringPool::Count() const
|
||||
{
|
||||
return m_Strings.Count();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
const char * CStringPool::Find( const char *pszValue )
|
||||
{
|
||||
unsigned short i = m_Strings.Find(pszValue);
|
||||
if ( m_Strings.IsValidIndex(i) )
|
||||
return m_Strings[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char * CStringPool::Allocate( const char *pszValue )
|
||||
{
|
||||
char *pszNew;
|
||||
|
||||
unsigned short i = m_Strings.Find(pszValue);
|
||||
bool bNew = (i == m_Strings.InvalidIndex());
|
||||
|
||||
if ( !bNew )
|
||||
return m_Strings[i];
|
||||
|
||||
pszNew = strdup( pszValue );
|
||||
|
||||
if ( bNew )
|
||||
m_Strings.Insert( pszNew );
|
||||
|
||||
return pszNew;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CStringPool::FreeAll()
|
||||
{
|
||||
unsigned short i = m_Strings.FirstInorder();
|
||||
while ( i != m_Strings.InvalidIndex() )
|
||||
{
|
||||
free( (void *)m_Strings[i] );
|
||||
i = m_Strings.NextInorder(i);
|
||||
}
|
||||
m_Strings.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
CCountedStringPool::CCountedStringPool()
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
m_HashTable.EnsureCount(HASH_TABLE_SIZE);
|
||||
|
||||
for( int i = 0; i < m_HashTable.Count(); i++ )
|
||||
{
|
||||
m_HashTable[i] = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
m_FreeListStart = INVALID_ELEMENT;
|
||||
m_Elements.AddToTail();
|
||||
m_Elements[0].pString = NULL;
|
||||
m_Elements[0].nReferenceCount = 0;
|
||||
m_Elements[0].nNextElement = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
CCountedStringPool::~CCountedStringPool()
|
||||
{
|
||||
FreeAll();
|
||||
}
|
||||
|
||||
void CCountedStringPool::FreeAll()
|
||||
{
|
||||
int i;
|
||||
|
||||
// Reset the hash table:
|
||||
for( i = 0; i < m_HashTable.Count(); i++ )
|
||||
{
|
||||
m_HashTable[i] = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
// Blow away the free list:
|
||||
m_FreeListStart = INVALID_ELEMENT;
|
||||
|
||||
for( i = 0; i < m_Elements.Count(); i++ )
|
||||
{
|
||||
if( m_Elements[i].pString )
|
||||
{
|
||||
delete [] m_Elements[i].pString;
|
||||
m_Elements[i].pString = NULL;
|
||||
m_Elements[i].nReferenceCount = 0;
|
||||
m_Elements[i].nNextElement = INVALID_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all but the invalid element:
|
||||
m_Elements.RemoveAll();
|
||||
m_Elements.AddToTail();
|
||||
m_Elements[0].pString = NULL;
|
||||
m_Elements[0].nReferenceCount = 0;
|
||||
m_Elements[0].nNextElement = INVALID_ELEMENT;
|
||||
}
|
||||
|
||||
|
||||
unsigned short CCountedStringPool::FindStringHandle( const char* pIntrinsic )
|
||||
{
|
||||
if( pIntrinsic == NULL )
|
||||
return INVALID_ELEMENT;
|
||||
|
||||
unsigned short nHashBucketIndex = (HashStringCaseless(pIntrinsic ) %HASH_TABLE_SIZE);
|
||||
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
|
||||
|
||||
// Does the bucket already exist?
|
||||
if( nCurrentBucket != INVALID_ELEMENT )
|
||||
{
|
||||
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
|
||||
{
|
||||
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
|
||||
{
|
||||
return nCurrentBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
char* CCountedStringPool::FindString( const char* pIntrinsic )
|
||||
{
|
||||
if( pIntrinsic == NULL )
|
||||
return NULL;
|
||||
|
||||
// Yes, this will be NULL on failure.
|
||||
return m_Elements[FindStringHandle(pIntrinsic)].pString;
|
||||
}
|
||||
|
||||
unsigned short CCountedStringPool::ReferenceStringHandle( const char* pIntrinsic )
|
||||
{
|
||||
if( pIntrinsic == NULL )
|
||||
return INVALID_ELEMENT;
|
||||
|
||||
unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % HASH_TABLE_SIZE);
|
||||
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
|
||||
|
||||
// Does the bucket already exist?
|
||||
if( nCurrentBucket != INVALID_ELEMENT )
|
||||
{
|
||||
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
|
||||
{
|
||||
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
|
||||
{
|
||||
// Anyone who hits 65k references is permanant
|
||||
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
|
||||
{
|
||||
m_Elements[nCurrentBucket].nReferenceCount ++ ;
|
||||
}
|
||||
return nCurrentBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_FreeListStart != INVALID_ELEMENT )
|
||||
{
|
||||
nCurrentBucket = m_FreeListStart;
|
||||
m_FreeListStart = m_Elements[nCurrentBucket].nNextElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
nCurrentBucket = m_Elements.AddToTail();
|
||||
}
|
||||
|
||||
m_Elements[nCurrentBucket].nReferenceCount = 1;
|
||||
|
||||
// Insert at the beginning of the bucket:
|
||||
m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ];
|
||||
m_HashTable[ nHashBucketIndex ] = nCurrentBucket;
|
||||
|
||||
m_Elements[nCurrentBucket].pString = new char[Q_strlen( pIntrinsic ) + 1];
|
||||
Q_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic );
|
||||
|
||||
return nCurrentBucket;
|
||||
}
|
||||
|
||||
|
||||
char* CCountedStringPool::ReferenceString( const char* pIntrinsic )
|
||||
{
|
||||
if(!pIntrinsic)
|
||||
return NULL;
|
||||
|
||||
return m_Elements[ReferenceStringHandle( pIntrinsic)].pString;
|
||||
}
|
||||
|
||||
void CCountedStringPool::DereferenceString( const char* pIntrinsic )
|
||||
{
|
||||
// If we get a NULL pointer, just return
|
||||
if (!pIntrinsic)
|
||||
return;
|
||||
|
||||
unsigned short nHashBucketIndex = (HashStringCaseless( pIntrinsic ) % m_HashTable.Count());
|
||||
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
|
||||
|
||||
// If there isn't anything in the bucket, just return.
|
||||
if ( nCurrentBucket == INVALID_ELEMENT )
|
||||
return;
|
||||
|
||||
for( unsigned short previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
|
||||
{
|
||||
if( !Q_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
|
||||
{
|
||||
// Anyone who hits 65k references is permanant
|
||||
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
|
||||
{
|
||||
m_Elements[nCurrentBucket].nReferenceCount --;
|
||||
}
|
||||
|
||||
if( m_Elements[nCurrentBucket].nReferenceCount == 0 )
|
||||
{
|
||||
if( previous == INVALID_ELEMENT )
|
||||
{
|
||||
m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement;
|
||||
}
|
||||
|
||||
delete [] m_Elements[nCurrentBucket].pString;
|
||||
m_Elements[nCurrentBucket].pString = NULL;
|
||||
m_Elements[nCurrentBucket].nReferenceCount = 0;
|
||||
|
||||
m_Elements[nCurrentBucket].nNextElement = m_FreeListStart;
|
||||
m_FreeListStart = nCurrentBucket;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
previous = nCurrentBucket;
|
||||
}
|
||||
}
|
||||
|
||||
char* CCountedStringPool::HandleToString( unsigned short handle )
|
||||
{
|
||||
return m_Elements[handle].pString;
|
||||
}
|
||||
|
||||
void CCountedStringPool::SpewStrings()
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < m_Elements.Count(); i++ )
|
||||
{
|
||||
char* string = m_Elements[i].pString;
|
||||
|
||||
Msg("String %d: ref:%d %s", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string);
|
||||
}
|
||||
|
||||
Msg("\n%d total counted strings.", m_Elements.Count());
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
CON_COMMAND( test_stringpool, "Tests the class CStringPool" )
|
||||
{
|
||||
CStringPool pool;
|
||||
|
||||
Assert(pool.Count() == 0);
|
||||
|
||||
pool.Allocate("test");
|
||||
Assert(pool.Count() == 1);
|
||||
|
||||
pool.Allocate("test");
|
||||
Assert(pool.Count() == 1);
|
||||
|
||||
pool.Allocate("test2");
|
||||
Assert(pool.Count() == 2);
|
||||
|
||||
Assert( pool.Find("test2") != NULL );
|
||||
Assert( pool.Find("TEST") != NULL );
|
||||
Assert( pool.Find("Test2") != NULL );
|
||||
Assert( pool.Find("test") != NULL );
|
||||
|
||||
pool.FreeAll();
|
||||
Assert(pool.Count() == 0);
|
||||
|
||||
Msg("Pass.");
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,63 +1,63 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A higher level link library for general use in the game and tools.
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include <tier1/tier1.h>
|
||||
#include "tier0/dbg.h"
|
||||
#include "vstdlib/iprocessutils.h"
|
||||
#include "icvar.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// These tier1 libraries must be set by any users of this library.
|
||||
// They can be set by calling ConnectTier1Libraries or InitDefaultFileSystem.
|
||||
// It is hoped that setting this, and using this library will be the common mechanism for
|
||||
// allowing link libraries to access tier1 library interfaces
|
||||
//-----------------------------------------------------------------------------
|
||||
ICvar *cvar = 0;
|
||||
ICvar *g_pCVar = 0;
|
||||
IProcessUtils *g_pProcessUtils = 0;
|
||||
static bool s_bConnected = false;
|
||||
|
||||
// for utlsortvector.h
|
||||
#ifndef _WIN32
|
||||
void *g_pUtlSortVectorQSortContext = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Call this to connect to all tier 1 libraries.
|
||||
// It's up to the caller to check the globals it cares about to see if ones are missing
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount )
|
||||
{
|
||||
// Don't connect twice..
|
||||
if ( s_bConnected )
|
||||
return;
|
||||
|
||||
s_bConnected = true;
|
||||
|
||||
for ( int i = 0; i < nFactoryCount; ++i )
|
||||
{
|
||||
if ( !g_pCVar )
|
||||
{
|
||||
cvar = g_pCVar = ( ICvar * )pFactoryList[i]( CVAR_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !g_pProcessUtils )
|
||||
{
|
||||
g_pProcessUtils = ( IProcessUtils * )pFactoryList[i]( PROCESS_UTILS_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisconnectTier1Libraries()
|
||||
{
|
||||
if ( !s_bConnected )
|
||||
return;
|
||||
|
||||
g_pCVar = cvar = 0;
|
||||
g_pProcessUtils = NULL;
|
||||
s_bConnected = false;
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A higher level link library for general use in the game and tools.
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include <tier1/tier1.h>
|
||||
#include "tier0/dbg.h"
|
||||
#include "vstdlib/iprocessutils.h"
|
||||
#include "icvar.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// These tier1 libraries must be set by any users of this library.
|
||||
// They can be set by calling ConnectTier1Libraries or InitDefaultFileSystem.
|
||||
// It is hoped that setting this, and using this library will be the common mechanism for
|
||||
// allowing link libraries to access tier1 library interfaces
|
||||
//-----------------------------------------------------------------------------
|
||||
ICvar *cvar = 0;
|
||||
ICvar *g_pCVar = 0;
|
||||
IProcessUtils *g_pProcessUtils = 0;
|
||||
static bool s_bConnected = false;
|
||||
|
||||
// for utlsortvector.h
|
||||
#ifndef _WIN32
|
||||
void *g_pUtlSortVectorQSortContext = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Call this to connect to all tier 1 libraries.
|
||||
// It's up to the caller to check the globals it cares about to see if ones are missing
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount )
|
||||
{
|
||||
// Don't connect twice..
|
||||
if ( s_bConnected )
|
||||
return;
|
||||
|
||||
s_bConnected = true;
|
||||
|
||||
for ( int i = 0; i < nFactoryCount; ++i )
|
||||
{
|
||||
if ( !g_pCVar )
|
||||
{
|
||||
cvar = g_pCVar = ( ICvar * )pFactoryList[i]( CVAR_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !g_pProcessUtils )
|
||||
{
|
||||
g_pProcessUtils = ( IProcessUtils * )pFactoryList[i]( PROCESS_UTILS_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisconnectTier1Libraries()
|
||||
{
|
||||
if ( !s_bConnected )
|
||||
return;
|
||||
|
||||
g_pCVar = cvar = 0;
|
||||
g_pProcessUtils = NULL;
|
||||
s_bConnected = false;
|
||||
}
|
||||
|
||||
@@ -1,152 +1,152 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// TIER1.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$macro SRCDIR ".."
|
||||
|
||||
$include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$PreprocessorDefinitions "$BASE;TIER1_STATIC_LIB"
|
||||
}
|
||||
|
||||
$Librarian [$WINDOWS]
|
||||
{
|
||||
$AdditionalDependencies "$BASE Rpcrt4.lib"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "tier1"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "bitbuf.cpp"
|
||||
$File "newbitbuf.cpp"
|
||||
$File "byteswap.cpp"
|
||||
$File "characterset.cpp"
|
||||
$File "checksum_crc.cpp"
|
||||
$File "checksum_md5.cpp"
|
||||
$File "checksum_sha1.cpp"
|
||||
$File "commandbuffer.cpp"
|
||||
$File "convar.cpp"
|
||||
$File "datamanager.cpp"
|
||||
$File "diff.cpp"
|
||||
$File "generichash.cpp"
|
||||
$File "ilocalize.cpp"
|
||||
$File "interface.cpp"
|
||||
$File "KeyValues.cpp"
|
||||
$File "kvpacker.cpp"
|
||||
$File "lzmaDecoder.cpp"
|
||||
$File "lzss.cpp" [!$SOURCESDK]
|
||||
$File "mempool.cpp"
|
||||
$File "memstack.cpp"
|
||||
$File "NetAdr.cpp"
|
||||
$File "splitstring.cpp"
|
||||
$File "processor_detect.cpp" [$WINDOWS||$X360]
|
||||
{
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$EnableC++Exceptions "Yes (/EHsc)" [!$X360]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$File "processor_detect_linux.cpp" [$POSIX]
|
||||
$File "qsort_s.cpp" [$LINUXALL||$PS3]
|
||||
$File "rangecheckedvar.cpp"
|
||||
$File "reliabletimer.cpp"
|
||||
$File "stringpool.cpp"
|
||||
$File "strtools.cpp"
|
||||
$File "tier1.cpp"
|
||||
$File "tokenreader.cpp"
|
||||
$File "sparsematrix.cpp"
|
||||
$File "uniqueid.cpp"
|
||||
$File "utlbuffer.cpp"
|
||||
$File "utlbufferutil.cpp"
|
||||
$File "utlstring.cpp"
|
||||
$File "utlsymbol.cpp"
|
||||
$File "pathmatch.cpp" [$LINUXALL]
|
||||
$File "snappy.cpp"
|
||||
$File "snappy-sinksource.cpp"
|
||||
$File "snappy-stubs-internal.cpp"
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$Folder "Internal Header Files"
|
||||
{
|
||||
$File "snappy-internal.h"
|
||||
$File "snappy-stubs-internal.h"
|
||||
}
|
||||
$File "$SRCDIR\public\tier1\bitbuf.h"
|
||||
$File "$SRCDIR\public\tier1\byteswap.h"
|
||||
$File "$SRCDIR\public\tier1\callqueue.h"
|
||||
$File "$SRCDIR\public\tier1\characterset.h"
|
||||
$File "$SRCDIR\public\tier1\checksum_crc.h"
|
||||
$File "$SRCDIR\public\tier1\checksum_md5.h"
|
||||
$File "$SRCDIR\public\tier1\checksum_sha1.h"
|
||||
$File "$SRCDIR\public\tier1\CommandBuffer.h"
|
||||
$File "$SRCDIR\public\tier1\convar.h"
|
||||
$File "$SRCDIR\public\tier1\datamanager.h"
|
||||
$File "$SRCDIR\public\datamap.h"
|
||||
$File "$SRCDIR\public\tier1\delegates.h"
|
||||
$File "$SRCDIR\public\tier1\diff.h"
|
||||
$File "$SRCDIR\public\tier1\fmtstr.h"
|
||||
$File "$SRCDIR\public\tier1\functors.h"
|
||||
$File "$SRCDIR\public\tier1\generichash.h"
|
||||
$File "$SRCDIR\public\tier1\iconvar.h"
|
||||
$File "$SRCDIR\public\tier1\ilocalize.h"
|
||||
$File "$SRCDIR\public\tier1\interface.h"
|
||||
$File "$SRCDIR\public\tier1\KeyValues.h"
|
||||
$File "$SRCDIR\public\tier1\kvpacker.h"
|
||||
$File "$SRCDIR\public\tier1\lzmaDecoder.h"
|
||||
$File "$SRCDIR\public\tier1\lzss.h"
|
||||
$File "$SRCDIR\public\tier1\mempool.h"
|
||||
$File "$SRCDIR\public\tier1\memstack.h"
|
||||
$File "$SRCDIR\public\tier1\netadr.h"
|
||||
$File "$SRCDIR\public\tier1\processor_detect.h"
|
||||
$File "$SRCDIR\public\tier1\rangecheckedvar.h"
|
||||
$File "$SRCDIR\public\tier1\refcount.h"
|
||||
$File "$SRCDIR\public\tier1\smartptr.h"
|
||||
$File "$SRCDIR\public\tier1\snappy.h"
|
||||
$File "$SRCDIR\public\tier1\snappy-sinksource.h"
|
||||
$File "$SRCDIR\public\tier1\stringpool.h"
|
||||
$File "$SRCDIR\public\tier1\strtools.h"
|
||||
$File "$SRCDIR\public\tier1\tier1.h"
|
||||
$File "$SRCDIR\public\tier1\tokenreader.h"
|
||||
$File "$SRCDIR\public\tier1\uniqueid.h" [$WINDOWS]
|
||||
$File "$SRCDIR\public\tier1\utlbidirectionalset.h"
|
||||
$File "$SRCDIR\public\tier1\utlblockmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlbuffer.h"
|
||||
$File "$SRCDIR\public\tier1\utlbufferutil.h"
|
||||
$File "$SRCDIR\public\tier1\utlcommon.h"
|
||||
$File "$SRCDIR\public\tier1\utldict.h"
|
||||
$File "$SRCDIR\public\tier1\utlenvelope.h"
|
||||
$File "$SRCDIR\public\tier1\utlfixedmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlhandletable.h"
|
||||
$File "$SRCDIR\public\tier1\utlhash.h"
|
||||
$File "$SRCDIR\public\tier1\utlhashtable.h"
|
||||
$File "$SRCDIR\public\tier1\utllinkedlist.h"
|
||||
$File "$SRCDIR\public\tier1\utlmap.h"
|
||||
$File "$SRCDIR\public\tier1\utlmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlmultilist.h"
|
||||
$File "$SRCDIR\public\tier1\utlpriorityqueue.h"
|
||||
$File "$SRCDIR\public\tier1\utlqueue.h"
|
||||
$File "$SRCDIR\public\tier1\utlrbtree.h"
|
||||
$File "$SRCDIR\public\tier1\UtlSortVector.h"
|
||||
$File "$SRCDIR\public\tier1\utlstack.h"
|
||||
$File "$SRCDIR\public\tier1\utlstring.h"
|
||||
$File "$SRCDIR\public\tier1\UtlStringMap.h"
|
||||
$File "$SRCDIR\public\tier1\utlsymbol.h"
|
||||
$File "$SRCDIR\public\tier1\utlsymbollarge.h"
|
||||
$File "$SRCDIR\public\tier1\utlvector.h"
|
||||
$File "$SRCDIR\common\xbox\xboxstubs.h" [$WINDOWS]
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// TIER1.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$macro SRCDIR ".."
|
||||
|
||||
$include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$PreprocessorDefinitions "$BASE;TIER1_STATIC_LIB"
|
||||
}
|
||||
|
||||
$Librarian [$WINDOWS]
|
||||
{
|
||||
$AdditionalDependencies "$BASE Rpcrt4.lib"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "tier1"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "bitbuf.cpp"
|
||||
$File "newbitbuf.cpp"
|
||||
$File "byteswap.cpp"
|
||||
$File "characterset.cpp"
|
||||
$File "checksum_crc.cpp"
|
||||
$File "checksum_md5.cpp"
|
||||
$File "checksum_sha1.cpp"
|
||||
$File "commandbuffer.cpp"
|
||||
$File "convar.cpp"
|
||||
$File "datamanager.cpp"
|
||||
$File "diff.cpp"
|
||||
$File "generichash.cpp"
|
||||
$File "ilocalize.cpp"
|
||||
$File "interface.cpp"
|
||||
$File "KeyValues.cpp"
|
||||
$File "kvpacker.cpp"
|
||||
$File "lzmaDecoder.cpp"
|
||||
$File "lzss.cpp" [!$SOURCESDK]
|
||||
$File "mempool.cpp"
|
||||
$File "memstack.cpp"
|
||||
$File "NetAdr.cpp"
|
||||
$File "splitstring.cpp"
|
||||
$File "processor_detect.cpp" [$WINDOWS||$X360]
|
||||
{
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$EnableC++Exceptions "Yes (/EHsc)" [!$X360]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$File "processor_detect_linux.cpp" [$POSIX]
|
||||
$File "qsort_s.cpp" [$LINUXALL||$PS3]
|
||||
$File "rangecheckedvar.cpp"
|
||||
$File "reliabletimer.cpp"
|
||||
$File "stringpool.cpp"
|
||||
$File "strtools.cpp"
|
||||
$File "tier1.cpp"
|
||||
$File "tokenreader.cpp"
|
||||
$File "sparsematrix.cpp"
|
||||
$File "uniqueid.cpp"
|
||||
$File "utlbuffer.cpp"
|
||||
$File "utlbufferutil.cpp"
|
||||
$File "utlstring.cpp"
|
||||
$File "utlsymbol.cpp"
|
||||
$File "pathmatch.cpp" [$LINUXALL]
|
||||
$File "snappy.cpp"
|
||||
$File "snappy-sinksource.cpp"
|
||||
$File "snappy-stubs-internal.cpp"
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$Folder "Internal Header Files"
|
||||
{
|
||||
$File "snappy-internal.h"
|
||||
$File "snappy-stubs-internal.h"
|
||||
}
|
||||
$File "$SRCDIR\public\tier1\bitbuf.h"
|
||||
$File "$SRCDIR\public\tier1\byteswap.h"
|
||||
$File "$SRCDIR\public\tier1\callqueue.h"
|
||||
$File "$SRCDIR\public\tier1\characterset.h"
|
||||
$File "$SRCDIR\public\tier1\checksum_crc.h"
|
||||
$File "$SRCDIR\public\tier1\checksum_md5.h"
|
||||
$File "$SRCDIR\public\tier1\checksum_sha1.h"
|
||||
$File "$SRCDIR\public\tier1\CommandBuffer.h"
|
||||
$File "$SRCDIR\public\tier1\convar.h"
|
||||
$File "$SRCDIR\public\tier1\datamanager.h"
|
||||
$File "$SRCDIR\public\datamap.h"
|
||||
$File "$SRCDIR\public\tier1\delegates.h"
|
||||
$File "$SRCDIR\public\tier1\diff.h"
|
||||
$File "$SRCDIR\public\tier1\fmtstr.h"
|
||||
$File "$SRCDIR\public\tier1\functors.h"
|
||||
$File "$SRCDIR\public\tier1\generichash.h"
|
||||
$File "$SRCDIR\public\tier1\iconvar.h"
|
||||
$File "$SRCDIR\public\tier1\ilocalize.h"
|
||||
$File "$SRCDIR\public\tier1\interface.h"
|
||||
$File "$SRCDIR\public\tier1\KeyValues.h"
|
||||
$File "$SRCDIR\public\tier1\kvpacker.h"
|
||||
$File "$SRCDIR\public\tier1\lzmaDecoder.h"
|
||||
$File "$SRCDIR\public\tier1\lzss.h"
|
||||
$File "$SRCDIR\public\tier1\mempool.h"
|
||||
$File "$SRCDIR\public\tier1\memstack.h"
|
||||
$File "$SRCDIR\public\tier1\netadr.h"
|
||||
$File "$SRCDIR\public\tier1\processor_detect.h"
|
||||
$File "$SRCDIR\public\tier1\rangecheckedvar.h"
|
||||
$File "$SRCDIR\public\tier1\refcount.h"
|
||||
$File "$SRCDIR\public\tier1\smartptr.h"
|
||||
$File "$SRCDIR\public\tier1\snappy.h"
|
||||
$File "$SRCDIR\public\tier1\snappy-sinksource.h"
|
||||
$File "$SRCDIR\public\tier1\stringpool.h"
|
||||
$File "$SRCDIR\public\tier1\strtools.h"
|
||||
$File "$SRCDIR\public\tier1\tier1.h"
|
||||
$File "$SRCDIR\public\tier1\tokenreader.h"
|
||||
$File "$SRCDIR\public\tier1\uniqueid.h" [$WINDOWS]
|
||||
$File "$SRCDIR\public\tier1\utlbidirectionalset.h"
|
||||
$File "$SRCDIR\public\tier1\utlblockmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlbuffer.h"
|
||||
$File "$SRCDIR\public\tier1\utlbufferutil.h"
|
||||
$File "$SRCDIR\public\tier1\utlcommon.h"
|
||||
$File "$SRCDIR\public\tier1\utldict.h"
|
||||
$File "$SRCDIR\public\tier1\utlenvelope.h"
|
||||
$File "$SRCDIR\public\tier1\utlfixedmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlhandletable.h"
|
||||
$File "$SRCDIR\public\tier1\utlhash.h"
|
||||
$File "$SRCDIR\public\tier1\utlhashtable.h"
|
||||
$File "$SRCDIR\public\tier1\utllinkedlist.h"
|
||||
$File "$SRCDIR\public\tier1\utlmap.h"
|
||||
$File "$SRCDIR\public\tier1\utlmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlmultilist.h"
|
||||
$File "$SRCDIR\public\tier1\utlpriorityqueue.h"
|
||||
$File "$SRCDIR\public\tier1\utlqueue.h"
|
||||
$File "$SRCDIR\public\tier1\utlrbtree.h"
|
||||
$File "$SRCDIR\public\tier1\UtlSortVector.h"
|
||||
$File "$SRCDIR\public\tier1\utlstack.h"
|
||||
$File "$SRCDIR\public\tier1\utlstring.h"
|
||||
$File "$SRCDIR\public\tier1\UtlStringMap.h"
|
||||
$File "$SRCDIR\public\tier1\utlsymbol.h"
|
||||
$File "$SRCDIR\public\tier1\utlsymbollarge.h"
|
||||
$File "$SRCDIR\public\tier1\utlvector.h"
|
||||
$File "$SRCDIR\common\xbox\xboxstubs.h" [$WINDOWS]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// tier1_exclude.vpc
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Project
|
||||
{
|
||||
$Folder "Link Libraries"
|
||||
{
|
||||
-$File "$SRCDIR\lib\$PLATFORM\tier1$_STATICLIB_EXT" [!$WINDOWS]
|
||||
-$File "$SRCDIR\lib\public\tier1$_STATICLIB_EXT" [$WINDOWS]
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// tier1_exclude.vpc
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Project
|
||||
{
|
||||
$Folder "Link Libraries"
|
||||
{
|
||||
-$File "$SRCDIR\lib\$PLATFORM\tier1$_STATICLIB_EXT" [!$WINDOWS]
|
||||
-$File "$SRCDIR\lib\public\tier1$_STATICLIB_EXT" [$WINDOWS]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,480 +1,480 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "tokenreader.h"
|
||||
#include "tier0/platform.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
TokenReader::TokenReader(void)
|
||||
{
|
||||
m_szFilename[0] = '\0';
|
||||
m_nLine = 1;
|
||||
m_nErrorCount = 0;
|
||||
m_bStuffed = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pszFilename -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TokenReader::Open(const char *pszFilename)
|
||||
{
|
||||
open(pszFilename, std::ios::in | std::ios::binary );
|
||||
Q_strncpy(m_szFilename, pszFilename, sizeof( m_szFilename ) );
|
||||
m_nLine = 1;
|
||||
m_nErrorCount = 0;
|
||||
m_bStuffed = false;
|
||||
return(is_open() != 0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void TokenReader::Close()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *error -
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *TokenReader::Error(char *error, ...)
|
||||
{
|
||||
static char szErrorBuf[256];
|
||||
Q_snprintf(szErrorBuf, sizeof( szErrorBuf ), "File %s, line %d: ", m_szFilename, m_nLine);
|
||||
Q_strncat(szErrorBuf, error, sizeof( szErrorBuf ), COPY_ALL_CHARACTERS );
|
||||
m_nErrorCount++;
|
||||
return(szErrorBuf);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszStore -
|
||||
// nSize -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::GetString(char *pszStore, int nSize)
|
||||
{
|
||||
if (nSize <= 0)
|
||||
{
|
||||
return TOKENERROR;
|
||||
}
|
||||
|
||||
char szBuf[1024];
|
||||
|
||||
//
|
||||
// Until we reach the end of this string or run out of room in
|
||||
// the destination buffer...
|
||||
//
|
||||
while (true)
|
||||
{
|
||||
//
|
||||
// Fetch the next batch of text from the file.
|
||||
//
|
||||
get(szBuf, sizeof(szBuf), '\"');
|
||||
if (eof())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
if (fail())
|
||||
{
|
||||
// Just means nothing was read (empty string probably "")
|
||||
clear();
|
||||
}
|
||||
|
||||
//
|
||||
// Transfer the text to the destination buffer.
|
||||
//
|
||||
char *pszSrc = szBuf;
|
||||
while ((*pszSrc != '\0') && (nSize > 1))
|
||||
{
|
||||
if (*pszSrc == 0x0d)
|
||||
{
|
||||
//
|
||||
// Newline encountered before closing quote -- unterminated string.
|
||||
//
|
||||
*pszStore = '\0';
|
||||
return TOKENSTRINGTOOLONG;
|
||||
}
|
||||
else if (*pszSrc != '\\')
|
||||
{
|
||||
*pszStore = *pszSrc;
|
||||
pszSrc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Backslash sequence - replace with the appropriate character.
|
||||
//
|
||||
pszSrc++;
|
||||
|
||||
if (*pszSrc == 'n')
|
||||
{
|
||||
*pszStore = '\n';
|
||||
}
|
||||
|
||||
pszSrc++;
|
||||
}
|
||||
|
||||
pszStore++;
|
||||
nSize--;
|
||||
}
|
||||
|
||||
if (*pszSrc != '\0')
|
||||
{
|
||||
//
|
||||
// Ran out of room in the destination buffer. Skip to the close-quote,
|
||||
// terminate the string, and exit.
|
||||
//
|
||||
ignore(1024, '\"');
|
||||
*pszStore = '\0';
|
||||
return TOKENSTRINGTOOLONG;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for closing quote.
|
||||
//
|
||||
if (peek() == '\"')
|
||||
{
|
||||
//
|
||||
// Eat the close quote and any whitespace.
|
||||
//
|
||||
get();
|
||||
|
||||
bool bCombineStrings = SkipWhiteSpace();
|
||||
|
||||
//
|
||||
// Combine consecutive quoted strings if the combine strings character was
|
||||
// encountered between the two strings.
|
||||
//
|
||||
if (bCombineStrings && (peek() == '\"'))
|
||||
{
|
||||
//
|
||||
// Eat the open quote and keep parsing this string.
|
||||
//
|
||||
get();
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Done with this string, terminate the string and exit.
|
||||
//
|
||||
*pszStore = '\0';
|
||||
return STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the next token, allocating enough memory to store the token
|
||||
// plus a terminating NULL.
|
||||
// Input : pszStore - Pointer to a string that will be allocated.
|
||||
// Output : Returns the type of token that was read, or TOKENERROR.
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::NextTokenDynamic(char **ppszStore)
|
||||
{
|
||||
char szTempBuffer[8192];
|
||||
trtoken_t eType = NextToken(szTempBuffer, sizeof(szTempBuffer));
|
||||
|
||||
int len = Q_strlen(szTempBuffer) + 1;
|
||||
*ppszStore = new char [len];
|
||||
Assert( *ppszStore );
|
||||
Q_strncpy(*ppszStore, szTempBuffer, len );
|
||||
|
||||
return(eType);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the next token.
|
||||
// Input : pszStore - Pointer to a string that will receive the token.
|
||||
// Output : Returns the type of token that was read, or TOKENERROR.
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::NextToken(char *pszStore, int nSize)
|
||||
{
|
||||
char *pStart = pszStore;
|
||||
|
||||
if (!is_open())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
//
|
||||
// If they stuffed a token, return that token.
|
||||
//
|
||||
if (m_bStuffed)
|
||||
{
|
||||
m_bStuffed = false;
|
||||
Q_strncpy( pszStore, m_szStuffed, nSize );
|
||||
return m_eStuffed;
|
||||
}
|
||||
|
||||
SkipWhiteSpace();
|
||||
|
||||
if (eof())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
if (fail())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
char ch = get();
|
||||
|
||||
//
|
||||
// Look for all the valid operators.
|
||||
//
|
||||
switch (ch)
|
||||
{
|
||||
case '@':
|
||||
case ',':
|
||||
case '!':
|
||||
case '+':
|
||||
case '&':
|
||||
case '*':
|
||||
case '$':
|
||||
case '.':
|
||||
case '=':
|
||||
case ':':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '{':
|
||||
case '}':
|
||||
case '\\':
|
||||
{
|
||||
pszStore[0] = ch;
|
||||
pszStore[1] = 0;
|
||||
return OPERATOR;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Look for the start of a quoted string.
|
||||
//
|
||||
if (ch == '\"')
|
||||
{
|
||||
return GetString(pszStore, nSize);
|
||||
}
|
||||
|
||||
//
|
||||
// Integers consist of numbers with an optional leading minus sign.
|
||||
//
|
||||
if (isdigit(ch) || (ch == '-'))
|
||||
{
|
||||
do
|
||||
{
|
||||
if ( (pszStore - pStart + 1) < nSize )
|
||||
{
|
||||
*pszStore = ch;
|
||||
pszStore++;
|
||||
}
|
||||
|
||||
ch = get();
|
||||
if (ch == '-')
|
||||
{
|
||||
return TOKENERROR;
|
||||
}
|
||||
} while (isdigit(ch));
|
||||
|
||||
//
|
||||
// No identifier characters are allowed contiguous with numbers.
|
||||
//
|
||||
if (isalpha(ch) || (ch == '_'))
|
||||
{
|
||||
return TOKENERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Put back the non-numeric character for the next call.
|
||||
//
|
||||
putback(ch);
|
||||
*pszStore = '\0';
|
||||
return INTEGER;
|
||||
}
|
||||
|
||||
//
|
||||
// Identifiers consist of a consecutive string of alphanumeric
|
||||
// characters and underscores.
|
||||
//
|
||||
while ( isalpha(ch) || isdigit(ch) || (ch == '_') )
|
||||
{
|
||||
if ( (pszStore - pStart + 1) < nSize )
|
||||
{
|
||||
*pszStore = ch;
|
||||
pszStore++;
|
||||
}
|
||||
|
||||
ch = get();
|
||||
}
|
||||
|
||||
//
|
||||
// Put back the non-identifier character for the next call.
|
||||
//
|
||||
putback(ch);
|
||||
*pszStore = '\0';
|
||||
return IDENT;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ttype -
|
||||
// *pszToken -
|
||||
//-----------------------------------------------------------------------------
|
||||
void TokenReader::IgnoreTill(trtoken_t ttype, const char *pszToken)
|
||||
{
|
||||
trtoken_t _ttype;
|
||||
char szBuf[1024];
|
||||
|
||||
while(1)
|
||||
{
|
||||
_ttype = NextToken(szBuf, sizeof(szBuf));
|
||||
if(_ttype == TOKENEOF)
|
||||
return;
|
||||
if(_ttype == ttype)
|
||||
{
|
||||
if(IsToken(pszToken, szBuf))
|
||||
{
|
||||
Stuff(ttype, pszToken);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ttype -
|
||||
// pszToken -
|
||||
//-----------------------------------------------------------------------------
|
||||
void TokenReader::Stuff(trtoken_t eType, const char *pszToken)
|
||||
{
|
||||
m_eStuffed = eType;
|
||||
Q_strncpy(m_szStuffed, pszToken, sizeof( m_szStuffed ) );
|
||||
m_bStuffed = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ttype -
|
||||
// pszToken -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TokenReader::Expecting(trtoken_t ttype, const char *pszToken)
|
||||
{
|
||||
char szBuf[1024];
|
||||
if (NextToken(szBuf, sizeof(szBuf)) != ttype || !IsToken(pszToken, szBuf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszStore -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::PeekTokenType(char *pszStore, int maxlen )
|
||||
{
|
||||
if (!m_bStuffed)
|
||||
{
|
||||
m_eStuffed = NextToken(m_szStuffed, sizeof(m_szStuffed));
|
||||
m_bStuffed = true;
|
||||
}
|
||||
|
||||
if (pszStore)
|
||||
{
|
||||
Q_strncpy(pszStore, m_szStuffed, maxlen );
|
||||
}
|
||||
|
||||
return(m_eStuffed);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets the next non-whitespace character from the file.
|
||||
// Input : ch - Receives the character.
|
||||
// Output : Returns true if the whitespace contained the combine strings
|
||||
// character '\', which is used to merge consecutive quoted strings.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TokenReader::SkipWhiteSpace(void)
|
||||
{
|
||||
bool bCombineStrings = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
char ch = get();
|
||||
|
||||
if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '+')
|
||||
{
|
||||
bCombineStrings = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '\n')
|
||||
{
|
||||
m_nLine++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (eof())
|
||||
{
|
||||
return(bCombineStrings);
|
||||
}
|
||||
|
||||
//
|
||||
// Check for the start of a comment.
|
||||
//
|
||||
if (ch == '/')
|
||||
{
|
||||
if (peek() == '/')
|
||||
{
|
||||
ignore(1024, '\n');
|
||||
m_nLine++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// It is a worthy character. Put it back.
|
||||
//
|
||||
putback(ch);
|
||||
return(bCombineStrings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "tokenreader.h"
|
||||
#include "tier0/platform.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
TokenReader::TokenReader(void)
|
||||
{
|
||||
m_szFilename[0] = '\0';
|
||||
m_nLine = 1;
|
||||
m_nErrorCount = 0;
|
||||
m_bStuffed = false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pszFilename -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TokenReader::Open(const char *pszFilename)
|
||||
{
|
||||
open(pszFilename, std::ios::in | std::ios::binary );
|
||||
Q_strncpy(m_szFilename, pszFilename, sizeof( m_szFilename ) );
|
||||
m_nLine = 1;
|
||||
m_nErrorCount = 0;
|
||||
m_bStuffed = false;
|
||||
return(is_open() != 0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void TokenReader::Close()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *error -
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *TokenReader::Error(char *error, ...)
|
||||
{
|
||||
static char szErrorBuf[256];
|
||||
Q_snprintf(szErrorBuf, sizeof( szErrorBuf ), "File %s, line %d: ", m_szFilename, m_nLine);
|
||||
Q_strncat(szErrorBuf, error, sizeof( szErrorBuf ), COPY_ALL_CHARACTERS );
|
||||
m_nErrorCount++;
|
||||
return(szErrorBuf);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszStore -
|
||||
// nSize -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::GetString(char *pszStore, int nSize)
|
||||
{
|
||||
if (nSize <= 0)
|
||||
{
|
||||
return TOKENERROR;
|
||||
}
|
||||
|
||||
char szBuf[1024];
|
||||
|
||||
//
|
||||
// Until we reach the end of this string or run out of room in
|
||||
// the destination buffer...
|
||||
//
|
||||
while (true)
|
||||
{
|
||||
//
|
||||
// Fetch the next batch of text from the file.
|
||||
//
|
||||
get(szBuf, sizeof(szBuf), '\"');
|
||||
if (eof())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
if (fail())
|
||||
{
|
||||
// Just means nothing was read (empty string probably "")
|
||||
clear();
|
||||
}
|
||||
|
||||
//
|
||||
// Transfer the text to the destination buffer.
|
||||
//
|
||||
char *pszSrc = szBuf;
|
||||
while ((*pszSrc != '\0') && (nSize > 1))
|
||||
{
|
||||
if (*pszSrc == 0x0d)
|
||||
{
|
||||
//
|
||||
// Newline encountered before closing quote -- unterminated string.
|
||||
//
|
||||
*pszStore = '\0';
|
||||
return TOKENSTRINGTOOLONG;
|
||||
}
|
||||
else if (*pszSrc != '\\')
|
||||
{
|
||||
*pszStore = *pszSrc;
|
||||
pszSrc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Backslash sequence - replace with the appropriate character.
|
||||
//
|
||||
pszSrc++;
|
||||
|
||||
if (*pszSrc == 'n')
|
||||
{
|
||||
*pszStore = '\n';
|
||||
}
|
||||
|
||||
pszSrc++;
|
||||
}
|
||||
|
||||
pszStore++;
|
||||
nSize--;
|
||||
}
|
||||
|
||||
if (*pszSrc != '\0')
|
||||
{
|
||||
//
|
||||
// Ran out of room in the destination buffer. Skip to the close-quote,
|
||||
// terminate the string, and exit.
|
||||
//
|
||||
ignore(1024, '\"');
|
||||
*pszStore = '\0';
|
||||
return TOKENSTRINGTOOLONG;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for closing quote.
|
||||
//
|
||||
if (peek() == '\"')
|
||||
{
|
||||
//
|
||||
// Eat the close quote and any whitespace.
|
||||
//
|
||||
get();
|
||||
|
||||
bool bCombineStrings = SkipWhiteSpace();
|
||||
|
||||
//
|
||||
// Combine consecutive quoted strings if the combine strings character was
|
||||
// encountered between the two strings.
|
||||
//
|
||||
if (bCombineStrings && (peek() == '\"'))
|
||||
{
|
||||
//
|
||||
// Eat the open quote and keep parsing this string.
|
||||
//
|
||||
get();
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Done with this string, terminate the string and exit.
|
||||
//
|
||||
*pszStore = '\0';
|
||||
return STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the next token, allocating enough memory to store the token
|
||||
// plus a terminating NULL.
|
||||
// Input : pszStore - Pointer to a string that will be allocated.
|
||||
// Output : Returns the type of token that was read, or TOKENERROR.
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::NextTokenDynamic(char **ppszStore)
|
||||
{
|
||||
char szTempBuffer[8192];
|
||||
trtoken_t eType = NextToken(szTempBuffer, sizeof(szTempBuffer));
|
||||
|
||||
int len = Q_strlen(szTempBuffer) + 1;
|
||||
*ppszStore = new char [len];
|
||||
Assert( *ppszStore );
|
||||
Q_strncpy(*ppszStore, szTempBuffer, len );
|
||||
|
||||
return(eType);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the next token.
|
||||
// Input : pszStore - Pointer to a string that will receive the token.
|
||||
// Output : Returns the type of token that was read, or TOKENERROR.
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::NextToken(char *pszStore, int nSize)
|
||||
{
|
||||
char *pStart = pszStore;
|
||||
|
||||
if (!is_open())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
//
|
||||
// If they stuffed a token, return that token.
|
||||
//
|
||||
if (m_bStuffed)
|
||||
{
|
||||
m_bStuffed = false;
|
||||
Q_strncpy( pszStore, m_szStuffed, nSize );
|
||||
return m_eStuffed;
|
||||
}
|
||||
|
||||
SkipWhiteSpace();
|
||||
|
||||
if (eof())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
if (fail())
|
||||
{
|
||||
return TOKENEOF;
|
||||
}
|
||||
|
||||
char ch = get();
|
||||
|
||||
//
|
||||
// Look for all the valid operators.
|
||||
//
|
||||
switch (ch)
|
||||
{
|
||||
case '@':
|
||||
case ',':
|
||||
case '!':
|
||||
case '+':
|
||||
case '&':
|
||||
case '*':
|
||||
case '$':
|
||||
case '.':
|
||||
case '=':
|
||||
case ':':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '{':
|
||||
case '}':
|
||||
case '\\':
|
||||
{
|
||||
pszStore[0] = ch;
|
||||
pszStore[1] = 0;
|
||||
return OPERATOR;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Look for the start of a quoted string.
|
||||
//
|
||||
if (ch == '\"')
|
||||
{
|
||||
return GetString(pszStore, nSize);
|
||||
}
|
||||
|
||||
//
|
||||
// Integers consist of numbers with an optional leading minus sign.
|
||||
//
|
||||
if (isdigit(ch) || (ch == '-'))
|
||||
{
|
||||
do
|
||||
{
|
||||
if ( (pszStore - pStart + 1) < nSize )
|
||||
{
|
||||
*pszStore = ch;
|
||||
pszStore++;
|
||||
}
|
||||
|
||||
ch = get();
|
||||
if (ch == '-')
|
||||
{
|
||||
return TOKENERROR;
|
||||
}
|
||||
} while (isdigit(ch));
|
||||
|
||||
//
|
||||
// No identifier characters are allowed contiguous with numbers.
|
||||
//
|
||||
if (isalpha(ch) || (ch == '_'))
|
||||
{
|
||||
return TOKENERROR;
|
||||
}
|
||||
|
||||
//
|
||||
// Put back the non-numeric character for the next call.
|
||||
//
|
||||
putback(ch);
|
||||
*pszStore = '\0';
|
||||
return INTEGER;
|
||||
}
|
||||
|
||||
//
|
||||
// Identifiers consist of a consecutive string of alphanumeric
|
||||
// characters and underscores.
|
||||
//
|
||||
while ( isalpha(ch) || isdigit(ch) || (ch == '_') )
|
||||
{
|
||||
if ( (pszStore - pStart + 1) < nSize )
|
||||
{
|
||||
*pszStore = ch;
|
||||
pszStore++;
|
||||
}
|
||||
|
||||
ch = get();
|
||||
}
|
||||
|
||||
//
|
||||
// Put back the non-identifier character for the next call.
|
||||
//
|
||||
putback(ch);
|
||||
*pszStore = '\0';
|
||||
return IDENT;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ttype -
|
||||
// *pszToken -
|
||||
//-----------------------------------------------------------------------------
|
||||
void TokenReader::IgnoreTill(trtoken_t ttype, const char *pszToken)
|
||||
{
|
||||
trtoken_t _ttype;
|
||||
char szBuf[1024];
|
||||
|
||||
while(1)
|
||||
{
|
||||
_ttype = NextToken(szBuf, sizeof(szBuf));
|
||||
if(_ttype == TOKENEOF)
|
||||
return;
|
||||
if(_ttype == ttype)
|
||||
{
|
||||
if(IsToken(pszToken, szBuf))
|
||||
{
|
||||
Stuff(ttype, pszToken);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ttype -
|
||||
// pszToken -
|
||||
//-----------------------------------------------------------------------------
|
||||
void TokenReader::Stuff(trtoken_t eType, const char *pszToken)
|
||||
{
|
||||
m_eStuffed = eType;
|
||||
Q_strncpy(m_szStuffed, pszToken, sizeof( m_szStuffed ) );
|
||||
m_bStuffed = true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : ttype -
|
||||
// pszToken -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TokenReader::Expecting(trtoken_t ttype, const char *pszToken)
|
||||
{
|
||||
char szBuf[1024];
|
||||
if (NextToken(szBuf, sizeof(szBuf)) != ttype || !IsToken(pszToken, szBuf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszStore -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t TokenReader::PeekTokenType(char *pszStore, int maxlen )
|
||||
{
|
||||
if (!m_bStuffed)
|
||||
{
|
||||
m_eStuffed = NextToken(m_szStuffed, sizeof(m_szStuffed));
|
||||
m_bStuffed = true;
|
||||
}
|
||||
|
||||
if (pszStore)
|
||||
{
|
||||
Q_strncpy(pszStore, m_szStuffed, maxlen );
|
||||
}
|
||||
|
||||
return(m_eStuffed);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets the next non-whitespace character from the file.
|
||||
// Input : ch - Receives the character.
|
||||
// Output : Returns true if the whitespace contained the combine strings
|
||||
// character '\', which is used to merge consecutive quoted strings.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool TokenReader::SkipWhiteSpace(void)
|
||||
{
|
||||
bool bCombineStrings = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
char ch = get();
|
||||
|
||||
if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '+')
|
||||
{
|
||||
bCombineStrings = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '\n')
|
||||
{
|
||||
m_nLine++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (eof())
|
||||
{
|
||||
return(bCombineStrings);
|
||||
}
|
||||
|
||||
//
|
||||
// Check for the start of a comment.
|
||||
//
|
||||
if (ch == '/')
|
||||
{
|
||||
if (peek() == '/')
|
||||
{
|
||||
ignore(1024, '\n');
|
||||
m_nLine++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// It is a worthy character. Put it back.
|
||||
//
|
||||
putback(ch);
|
||||
return(bCombineStrings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// UnDiff - Apply difference block
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/diff.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList,
|
||||
int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize)
|
||||
{
|
||||
uint8 const *copy_src=OldBlock;
|
||||
uint8 const *end_of_diff_list=DiffList+DiffListSize;
|
||||
uint8 const *obuf=Output;
|
||||
while(DiffList<end_of_diff_list)
|
||||
{
|
||||
// printf("dptr=%x ",DiffList-d);
|
||||
uint8 op=*(DiffList++);
|
||||
if (op==0)
|
||||
{
|
||||
uint16 copy_sz=DiffList[0]+256*DiffList[1];
|
||||
int copy_ofs=DiffList[2]+DiffList[3]*256;
|
||||
if (copy_ofs>32767)
|
||||
copy_ofs|=0xffff0000;
|
||||
// printf("long cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
|
||||
|
||||
memcpy(Output,copy_src+copy_ofs,copy_sz);
|
||||
Output+=copy_sz;
|
||||
copy_src=copy_src+copy_ofs+copy_sz;
|
||||
DiffList+=4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (op & 0x80)
|
||||
{
|
||||
int copy_sz=op & 0x7f;
|
||||
int copy_ofs;
|
||||
if (copy_sz==0)
|
||||
{
|
||||
copy_sz=DiffList[0];
|
||||
if (copy_sz==0)
|
||||
{
|
||||
// big raw copy
|
||||
copy_sz=DiffList[1]+256*DiffList[2]+65536*DiffList[3];
|
||||
memcpy(Output,DiffList+4,copy_sz);
|
||||
// printf("big rawcopy to %x len=%d\n", Output-obuf,copy_sz);
|
||||
|
||||
DiffList+=copy_sz+4;
|
||||
Output+=copy_sz;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_ofs=DiffList[1]+(DiffList[2]*256);
|
||||
if (copy_ofs>32767)
|
||||
copy_ofs|=0xffff0000;
|
||||
// printf("long ofs cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
|
||||
|
||||
memcpy(Output,copy_src+copy_ofs,copy_sz);
|
||||
Output+=copy_sz;
|
||||
copy_src=copy_src+copy_ofs+copy_sz;
|
||||
DiffList+=3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_ofs=DiffList[0];
|
||||
if (copy_ofs>127)
|
||||
copy_ofs|=0xffffff80;
|
||||
// printf("cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
|
||||
|
||||
memcpy(Output,copy_src+copy_ofs,copy_sz);
|
||||
Output+=copy_sz;
|
||||
copy_src=copy_src+copy_ofs+copy_sz;
|
||||
DiffList++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("raw copy %d to %x\n",op & 127,Output-obuf);
|
||||
memcpy(Output,DiffList,op & 127);
|
||||
Output+=op & 127;
|
||||
DiffList+=(op & 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
ResultListSize=Output-obuf;
|
||||
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// UnDiff - Apply difference block
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/diff.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
void ApplyDiffs(uint8 const *OldBlock, uint8 const *DiffList,
|
||||
int OldSize, int DiffListSize, int &ResultListSize,uint8 *Output,uint32 OutSize)
|
||||
{
|
||||
uint8 const *copy_src=OldBlock;
|
||||
uint8 const *end_of_diff_list=DiffList+DiffListSize;
|
||||
uint8 const *obuf=Output;
|
||||
while(DiffList<end_of_diff_list)
|
||||
{
|
||||
// printf("dptr=%x ",DiffList-d);
|
||||
uint8 op=*(DiffList++);
|
||||
if (op==0)
|
||||
{
|
||||
uint16 copy_sz=DiffList[0]+256*DiffList[1];
|
||||
int copy_ofs=DiffList[2]+DiffList[3]*256;
|
||||
if (copy_ofs>32767)
|
||||
copy_ofs|=0xffff0000;
|
||||
// printf("long cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
|
||||
|
||||
memcpy(Output,copy_src+copy_ofs,copy_sz);
|
||||
Output+=copy_sz;
|
||||
copy_src=copy_src+copy_ofs+copy_sz;
|
||||
DiffList+=4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (op & 0x80)
|
||||
{
|
||||
int copy_sz=op & 0x7f;
|
||||
int copy_ofs;
|
||||
if (copy_sz==0)
|
||||
{
|
||||
copy_sz=DiffList[0];
|
||||
if (copy_sz==0)
|
||||
{
|
||||
// big raw copy
|
||||
copy_sz=DiffList[1]+256*DiffList[2]+65536*DiffList[3];
|
||||
memcpy(Output,DiffList+4,copy_sz);
|
||||
// printf("big rawcopy to %x len=%d\n", Output-obuf,copy_sz);
|
||||
|
||||
DiffList+=copy_sz+4;
|
||||
Output+=copy_sz;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_ofs=DiffList[1]+(DiffList[2]*256);
|
||||
if (copy_ofs>32767)
|
||||
copy_ofs|=0xffff0000;
|
||||
// printf("long ofs cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
|
||||
|
||||
memcpy(Output,copy_src+copy_ofs,copy_sz);
|
||||
Output+=copy_sz;
|
||||
copy_src=copy_src+copy_ofs+copy_sz;
|
||||
DiffList+=3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_ofs=DiffList[0];
|
||||
if (copy_ofs>127)
|
||||
copy_ofs|=0xffffff80;
|
||||
// printf("cp from %x to %x len=%d\n", copy_src+copy_ofs-OldBlock,Output-obuf,copy_sz);
|
||||
|
||||
memcpy(Output,copy_src+copy_ofs,copy_sz);
|
||||
Output+=copy_sz;
|
||||
copy_src=copy_src+copy_ofs+copy_sz;
|
||||
DiffList++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("raw copy %d to %x\n",op & 127,Output-obuf);
|
||||
memcpy(Output,DiffList,op & 127);
|
||||
Output+=op & 127;
|
||||
DiffList+=(op & 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
ResultListSize=Output-obuf;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,177 +1,177 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
// Unique ID generation
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier0/platform.h"
|
||||
|
||||
#ifdef IS_WINDOWS_PC
|
||||
#include <windows.h> // UUIDCreate
|
||||
#else
|
||||
#include "checksum_crc.h"
|
||||
#endif
|
||||
#include "tier1/uniqueid.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new unique id
|
||||
//-----------------------------------------------------------------------------
|
||||
void CreateUniqueId( UniqueId_t *pDest )
|
||||
{
|
||||
#ifdef IS_WINDOWS_PC
|
||||
Assert( sizeof( UUID ) == sizeof( *pDest ) );
|
||||
UuidCreate( (UUID *)pDest );
|
||||
#else
|
||||
// X360/linux TBD: Need a real UUID Implementation
|
||||
Q_memset( pDest, 0, sizeof( UniqueId_t ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new unique id from a string representation of one
|
||||
//-----------------------------------------------------------------------------
|
||||
bool UniqueIdFromString( UniqueId_t *pDest, const char *pBuf, int nMaxLen )
|
||||
{
|
||||
if ( nMaxLen == 0 )
|
||||
{
|
||||
nMaxLen = Q_strlen( pBuf );
|
||||
}
|
||||
|
||||
char *pTemp = (char*)stackalloc( nMaxLen + 1 );
|
||||
V_strncpy( pTemp, pBuf, nMaxLen + 1 );
|
||||
--nMaxLen;
|
||||
while( (nMaxLen >= 0) && isspace( pTemp[nMaxLen] ) )
|
||||
{
|
||||
--nMaxLen;
|
||||
}
|
||||
pTemp[ nMaxLen + 1 ] = 0;
|
||||
|
||||
while( *pTemp && isspace( *pTemp ) )
|
||||
{
|
||||
++pTemp;
|
||||
}
|
||||
|
||||
#ifdef IS_WINDOWS_PC
|
||||
Assert( sizeof( UUID ) == sizeof( *pDest ) );
|
||||
|
||||
if ( RPC_S_OK != UuidFromString( (unsigned char *)pTemp, (UUID *)pDest ) )
|
||||
{
|
||||
InvalidateUniqueId( pDest );
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// X360TBD: Need a real UUID Implementation
|
||||
// For now, use crc to generate a unique ID from the UUID string.
|
||||
Q_memset( pDest, 0, sizeof( UniqueId_t ) );
|
||||
if ( nMaxLen > 0 )
|
||||
{
|
||||
CRC32_t crc;
|
||||
CRC32_Init( &crc );
|
||||
CRC32_ProcessBuffer( &crc, pBuf, nMaxLen );
|
||||
CRC32_Final( &crc );
|
||||
Q_memcpy( pDest, &crc, sizeof( CRC32_t ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets an object ID to be an invalid state
|
||||
//-----------------------------------------------------------------------------
|
||||
void InvalidateUniqueId( UniqueId_t *pDest )
|
||||
{
|
||||
Assert( pDest );
|
||||
memset( pDest, 0, sizeof( UniqueId_t ) );
|
||||
}
|
||||
|
||||
bool IsUniqueIdValid( const UniqueId_t &id )
|
||||
{
|
||||
UniqueId_t invalidId;
|
||||
memset( &invalidId, 0, sizeof( UniqueId_t ) );
|
||||
return !IsUniqueIdEqual( invalidId, id );
|
||||
}
|
||||
|
||||
bool IsUniqueIdEqual( const UniqueId_t &id1, const UniqueId_t &id2 )
|
||||
{
|
||||
return memcmp( &id1, &id2, sizeof( UniqueId_t ) ) == 0;
|
||||
}
|
||||
|
||||
void UniqueIdToString( const UniqueId_t &id, char *pBuf, int nMaxLen )
|
||||
{
|
||||
pBuf[ 0 ] = 0;
|
||||
|
||||
// X360TBD: Need a real UUID Implementation
|
||||
#ifdef IS_WINDOWS_PC
|
||||
UUID *self = ( UUID * )&id;
|
||||
|
||||
unsigned char *outstring = NULL;
|
||||
|
||||
UuidToString( self, &outstring );
|
||||
if ( outstring && *outstring )
|
||||
{
|
||||
Q_strncpy( pBuf, (const char *)outstring, nMaxLen );
|
||||
RpcStringFree( &outstring );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CopyUniqueId( const UniqueId_t &src, UniqueId_t *pDest )
|
||||
{
|
||||
memcpy( pDest, &src, sizeof( UniqueId_t ) );
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const UniqueId_t &src )
|
||||
{
|
||||
// X360TBD: Need a real UUID Implementation
|
||||
#ifdef IS_WINDOWS_PC
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
UUID *pId = ( UUID * )&src;
|
||||
|
||||
unsigned char *outstring = NULL;
|
||||
|
||||
UuidToString( pId, &outstring );
|
||||
if ( outstring && *outstring )
|
||||
{
|
||||
buf.PutString( (const char *)outstring );
|
||||
RpcStringFree( &outstring );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutChar( '\0' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.Put( &src, sizeof(UniqueId_t) );
|
||||
}
|
||||
return buf.IsValid();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, UniqueId_t &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
int nTextLen = buf.PeekStringLength();
|
||||
char *pBuf = (char*)stackalloc( nTextLen );
|
||||
buf.GetString( pBuf, nTextLen );
|
||||
UniqueIdFromString( &dest, pBuf, nTextLen );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.Get( &dest, sizeof(UniqueId_t) );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
// Unique ID generation
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier0/platform.h"
|
||||
|
||||
#ifdef IS_WINDOWS_PC
|
||||
#include <windows.h> // UUIDCreate
|
||||
#else
|
||||
#include "checksum_crc.h"
|
||||
#endif
|
||||
#include "tier1/uniqueid.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new unique id
|
||||
//-----------------------------------------------------------------------------
|
||||
void CreateUniqueId( UniqueId_t *pDest )
|
||||
{
|
||||
#ifdef IS_WINDOWS_PC
|
||||
Assert( sizeof( UUID ) == sizeof( *pDest ) );
|
||||
UuidCreate( (UUID *)pDest );
|
||||
#else
|
||||
// X360/linux TBD: Need a real UUID Implementation
|
||||
Q_memset( pDest, 0, sizeof( UniqueId_t ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new unique id from a string representation of one
|
||||
//-----------------------------------------------------------------------------
|
||||
bool UniqueIdFromString( UniqueId_t *pDest, const char *pBuf, int nMaxLen )
|
||||
{
|
||||
if ( nMaxLen == 0 )
|
||||
{
|
||||
nMaxLen = Q_strlen( pBuf );
|
||||
}
|
||||
|
||||
char *pTemp = (char*)stackalloc( nMaxLen + 1 );
|
||||
V_strncpy( pTemp, pBuf, nMaxLen + 1 );
|
||||
--nMaxLen;
|
||||
while( (nMaxLen >= 0) && isspace( pTemp[nMaxLen] ) )
|
||||
{
|
||||
--nMaxLen;
|
||||
}
|
||||
pTemp[ nMaxLen + 1 ] = 0;
|
||||
|
||||
while( *pTemp && isspace( *pTemp ) )
|
||||
{
|
||||
++pTemp;
|
||||
}
|
||||
|
||||
#ifdef IS_WINDOWS_PC
|
||||
Assert( sizeof( UUID ) == sizeof( *pDest ) );
|
||||
|
||||
if ( RPC_S_OK != UuidFromString( (unsigned char *)pTemp, (UUID *)pDest ) )
|
||||
{
|
||||
InvalidateUniqueId( pDest );
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// X360TBD: Need a real UUID Implementation
|
||||
// For now, use crc to generate a unique ID from the UUID string.
|
||||
Q_memset( pDest, 0, sizeof( UniqueId_t ) );
|
||||
if ( nMaxLen > 0 )
|
||||
{
|
||||
CRC32_t crc;
|
||||
CRC32_Init( &crc );
|
||||
CRC32_ProcessBuffer( &crc, pBuf, nMaxLen );
|
||||
CRC32_Final( &crc );
|
||||
Q_memcpy( pDest, &crc, sizeof( CRC32_t ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets an object ID to be an invalid state
|
||||
//-----------------------------------------------------------------------------
|
||||
void InvalidateUniqueId( UniqueId_t *pDest )
|
||||
{
|
||||
Assert( pDest );
|
||||
memset( pDest, 0, sizeof( UniqueId_t ) );
|
||||
}
|
||||
|
||||
bool IsUniqueIdValid( const UniqueId_t &id )
|
||||
{
|
||||
UniqueId_t invalidId;
|
||||
memset( &invalidId, 0, sizeof( UniqueId_t ) );
|
||||
return !IsUniqueIdEqual( invalidId, id );
|
||||
}
|
||||
|
||||
bool IsUniqueIdEqual( const UniqueId_t &id1, const UniqueId_t &id2 )
|
||||
{
|
||||
return memcmp( &id1, &id2, sizeof( UniqueId_t ) ) == 0;
|
||||
}
|
||||
|
||||
void UniqueIdToString( const UniqueId_t &id, char *pBuf, int nMaxLen )
|
||||
{
|
||||
pBuf[ 0 ] = 0;
|
||||
|
||||
// X360TBD: Need a real UUID Implementation
|
||||
#ifdef IS_WINDOWS_PC
|
||||
UUID *self = ( UUID * )&id;
|
||||
|
||||
unsigned char *outstring = NULL;
|
||||
|
||||
UuidToString( self, &outstring );
|
||||
if ( outstring && *outstring )
|
||||
{
|
||||
Q_strncpy( pBuf, (const char *)outstring, nMaxLen );
|
||||
RpcStringFree( &outstring );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CopyUniqueId( const UniqueId_t &src, UniqueId_t *pDest )
|
||||
{
|
||||
memcpy( pDest, &src, sizeof( UniqueId_t ) );
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const UniqueId_t &src )
|
||||
{
|
||||
// X360TBD: Need a real UUID Implementation
|
||||
#ifdef IS_WINDOWS_PC
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
UUID *pId = ( UUID * )&src;
|
||||
|
||||
unsigned char *outstring = NULL;
|
||||
|
||||
UuidToString( pId, &outstring );
|
||||
if ( outstring && *outstring )
|
||||
{
|
||||
buf.PutString( (const char *)outstring );
|
||||
RpcStringFree( &outstring );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutChar( '\0' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.Put( &src, sizeof(UniqueId_t) );
|
||||
}
|
||||
return buf.IsValid();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, UniqueId_t &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
int nTextLen = buf.PeekStringLength();
|
||||
char *pBuf = (char*)stackalloc( nTextLen );
|
||||
buf.GetString( pBuf, nTextLen );
|
||||
UniqueIdFromString( &dest, pBuf, nTextLen );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.Get( &dest, sizeof(UniqueId_t) );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,436 +1,436 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Defines a symbol table
|
||||
//
|
||||
// $Header: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#pragma warning (disable:4514)
|
||||
|
||||
#include "utlsymbol.h"
|
||||
#include "KeyValues.h"
|
||||
#include "tier0/threadtools.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
#include "stringpool.h"
|
||||
#include "utlhashtable.h"
|
||||
#include "utlstring.h"
|
||||
|
||||
// Ensure that everybody has the right compiler version installed. The version
|
||||
// number can be obtained by looking at the compiler output when you type 'cl'
|
||||
// and removing the last two digits and the periods: 16.00.40219.01 becomes 160040219
|
||||
#ifdef _MSC_FULL_VER
|
||||
#if _MSC_FULL_VER > 160000000
|
||||
// VS 2010
|
||||
#if _MSC_FULL_VER < 160040219
|
||||
#error You must install VS 2010 SP1
|
||||
#endif
|
||||
#else
|
||||
// VS 2005
|
||||
#if _MSC_FULL_VER < 140050727
|
||||
#error You must install VS 2005 SP1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define INVALID_STRING_INDEX CStringPoolIndex( 0xFFFF, 0xFFFF )
|
||||
|
||||
#define MIN_STRING_POOL_SIZE 2048
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// globals
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbolTableMT* CUtlSymbol::s_pSymbolTable = 0;
|
||||
bool CUtlSymbol::s_bAllowStaticSymbolTable = true;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// symbol methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlSymbol::Initialize()
|
||||
{
|
||||
// If this assert fails, then the module that this call is in has chosen to disallow
|
||||
// use of the static symbol table. Usually, it's to prevent confusion because it's easy
|
||||
// to accidentally use the global symbol table when you really want to use a specific one.
|
||||
Assert( s_bAllowStaticSymbolTable );
|
||||
|
||||
// necessary to allow us to create global symbols
|
||||
static bool symbolsInitialized = false;
|
||||
if (!symbolsInitialized)
|
||||
{
|
||||
s_pSymbolTable = new CUtlSymbolTableMT;
|
||||
symbolsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Singleton to delete table on exit from module
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCleanupUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
~CCleanupUtlSymbolTable()
|
||||
{
|
||||
delete CUtlSymbol::s_pSymbolTable;
|
||||
CUtlSymbol::s_pSymbolTable = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static CCleanupUtlSymbolTable g_CleanupSymbolTable;
|
||||
|
||||
CUtlSymbolTableMT* CUtlSymbol::CurrTable()
|
||||
{
|
||||
Initialize();
|
||||
return s_pSymbolTable;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// string->symbol->string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbol::CUtlSymbol( const char* pStr )
|
||||
{
|
||||
m_Id = CurrTable()->AddString( pStr );
|
||||
}
|
||||
|
||||
const char* CUtlSymbol::String( ) const
|
||||
{
|
||||
return CurrTable()->String(m_Id);
|
||||
}
|
||||
|
||||
void CUtlSymbol::DisableStaticSymbolTable()
|
||||
{
|
||||
s_bAllowStaticSymbolTable = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// checks if the symbol matches a string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool CUtlSymbol::operator==( const char* pStr ) const
|
||||
{
|
||||
if (m_Id == UTL_INVAL_SYMBOL)
|
||||
return false;
|
||||
return strcmp( String(), pStr ) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// symbol table stuff
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const
|
||||
{
|
||||
Assert( index.m_iPool < m_StringPools.Count() );
|
||||
Assert( index.m_iOffset < m_StringPools[index.m_iPool]->m_TotalLen );
|
||||
|
||||
return &m_StringPools[index.m_iPool]->m_Data[index.m_iOffset];
|
||||
}
|
||||
|
||||
|
||||
bool CUtlSymbolTable::CLess::operator()( const CStringPoolIndex &i1, const CStringPoolIndex &i2 ) const
|
||||
{
|
||||
// Need to do pointer math because CUtlSymbolTable is used in CUtlVectors, and hence
|
||||
// can be arbitrarily moved in memory on a realloc. Yes, this is portable. In reality,
|
||||
// right now at least, because m_LessFunc is the first member of CUtlRBTree, and m_Lookup
|
||||
// is the first member of CUtlSymbolTabke, this == pTable
|
||||
CUtlSymbolTable *pTable = (CUtlSymbolTable *)( (byte *)this - offsetof(CUtlSymbolTable::CTree, m_LessFunc) ) - offsetof(CUtlSymbolTable, m_Lookup );
|
||||
const char* str1 = (i1 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
|
||||
pTable->StringFromIndex( i1 );
|
||||
const char* str2 = (i2 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
|
||||
pTable->StringFromIndex( i2 );
|
||||
|
||||
if ( !str1 && str2 )
|
||||
return false;
|
||||
if ( !str2 && str1 )
|
||||
return true;
|
||||
if ( !str1 && !str2 )
|
||||
return false;
|
||||
if ( !pTable->m_bInsensitive )
|
||||
return V_strcmp( str1, str2 ) < 0;
|
||||
else
|
||||
return V_stricmp( str1, str2 ) < 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlSymbolTable::CUtlSymbolTable( int growSize, int initSize, bool caseInsensitive ) :
|
||||
m_Lookup( growSize, initSize ), m_bInsensitive( caseInsensitive ), m_StringPools( 8 )
|
||||
{
|
||||
}
|
||||
|
||||
CUtlSymbolTable::~CUtlSymbolTable()
|
||||
{
|
||||
// Release the stringpool string data
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
CUtlSymbol CUtlSymbolTable::Find( const char* pString ) const
|
||||
{
|
||||
if (!pString)
|
||||
return CUtlSymbol();
|
||||
|
||||
// Store a special context used to help with insertion
|
||||
m_pUserSearchString = pString;
|
||||
|
||||
// Passing this special invalid symbol makes the comparison function
|
||||
// use the string passed in the context
|
||||
UtlSymId_t idx = m_Lookup.Find( INVALID_STRING_INDEX );
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_pUserSearchString = NULL;
|
||||
#endif
|
||||
|
||||
return CUtlSymbol( idx );
|
||||
}
|
||||
|
||||
|
||||
int CUtlSymbolTable::FindPoolWithSpace( int len ) const
|
||||
{
|
||||
for ( int i=0; i < m_StringPools.Count(); i++ )
|
||||
{
|
||||
StringPool_t *pPool = m_StringPools[i];
|
||||
|
||||
if ( (pPool->m_TotalLen - pPool->m_SpaceUsed) >= len )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds and/or creates a symbol based on the string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbol CUtlSymbolTable::AddString( const char* pString )
|
||||
{
|
||||
if (!pString)
|
||||
return CUtlSymbol( UTL_INVAL_SYMBOL );
|
||||
|
||||
CUtlSymbol id = Find( pString );
|
||||
|
||||
if (id.IsValid())
|
||||
return id;
|
||||
|
||||
int len = strlen(pString) + 1;
|
||||
|
||||
// Find a pool with space for this string, or allocate a new one.
|
||||
int iPool = FindPoolWithSpace( len );
|
||||
if ( iPool == -1 )
|
||||
{
|
||||
// Add a new pool.
|
||||
int newPoolSize = max( len, MIN_STRING_POOL_SIZE );
|
||||
StringPool_t *pPool = (StringPool_t*)malloc( sizeof( StringPool_t ) + newPoolSize - 1 );
|
||||
pPool->m_TotalLen = newPoolSize;
|
||||
pPool->m_SpaceUsed = 0;
|
||||
iPool = m_StringPools.AddToTail( pPool );
|
||||
}
|
||||
|
||||
// Copy the string in.
|
||||
StringPool_t *pPool = m_StringPools[iPool];
|
||||
Assert( pPool->m_SpaceUsed < 0xFFFF ); // This should never happen, because if we had a string > 64k, it
|
||||
// would have been given its entire own pool.
|
||||
|
||||
unsigned short iStringOffset = pPool->m_SpaceUsed;
|
||||
|
||||
memcpy( &pPool->m_Data[pPool->m_SpaceUsed], pString, len );
|
||||
pPool->m_SpaceUsed += len;
|
||||
|
||||
// didn't find, insert the string into the vector.
|
||||
CStringPoolIndex index;
|
||||
index.m_iPool = iPool;
|
||||
index.m_iOffset = iStringOffset;
|
||||
|
||||
UtlSymId_t idx = m_Lookup.Insert( index );
|
||||
return CUtlSymbol( idx );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Look up the string associated with a particular symbol
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const char* CUtlSymbolTable::String( CUtlSymbol id ) const
|
||||
{
|
||||
if (!id.IsValid())
|
||||
return "";
|
||||
|
||||
Assert( m_Lookup.IsValidIndex((UtlSymId_t)id) );
|
||||
return StringFromIndex( m_Lookup[id] );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Remove all symbols in the table.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlSymbolTable::RemoveAll()
|
||||
{
|
||||
m_Lookup.Purge();
|
||||
|
||||
for ( int i=0; i < m_StringPools.Count(); i++ )
|
||||
free( m_StringPools[i] );
|
||||
|
||||
m_StringPools.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CUtlFilenameSymbolTable::HashTable : public CUtlStableHashtable<CUtlConstString>
|
||||
{
|
||||
};
|
||||
|
||||
CUtlFilenameSymbolTable::CUtlFilenameSymbolTable()
|
||||
{
|
||||
m_Strings = new HashTable;
|
||||
}
|
||||
|
||||
CUtlFilenameSymbolTable::~CUtlFilenameSymbolTable()
|
||||
{
|
||||
delete m_Strings;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pFileName -
|
||||
// Output : FileNameHandle_t
|
||||
//-----------------------------------------------------------------------------
|
||||
FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileName )
|
||||
{
|
||||
if ( !pFileName )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find first
|
||||
FileNameHandle_t hFileName = FindFileName( pFileName );
|
||||
if ( hFileName )
|
||||
{
|
||||
return hFileName;
|
||||
}
|
||||
|
||||
// Fix slashes+dotslashes and make lower case first..
|
||||
char fn[ MAX_PATH ];
|
||||
Q_strncpy( fn, pFileName, sizeof( fn ) );
|
||||
Q_RemoveDotSlashes( fn );
|
||||
#ifdef _WIN32
|
||||
Q_strlower( fn );
|
||||
#endif
|
||||
|
||||
// Split the filename into constituent parts
|
||||
char basepath[ MAX_PATH ];
|
||||
Q_ExtractFilePath( fn, basepath, sizeof( basepath ) );
|
||||
char filename[ MAX_PATH ];
|
||||
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
|
||||
|
||||
// not found, lock and look again
|
||||
FileNameHandleInternal_t handle;
|
||||
m_lock.LockForWrite();
|
||||
handle.path = m_Strings->Insert( basepath ) + 1;
|
||||
handle.file = m_Strings->Insert( filename ) + 1;
|
||||
//handle.path = m_StringPool.FindStringHandle( basepath );
|
||||
//handle.file = m_StringPool.FindStringHandle( filename );
|
||||
//if ( handle.path != m_Strings.InvalidHandle() && handle.file )
|
||||
//{
|
||||
// found
|
||||
// m_lock.UnlockWrite();
|
||||
// return *( FileNameHandle_t * )( &handle );
|
||||
//}
|
||||
|
||||
// safely add it
|
||||
//handle.path = m_StringPool.ReferenceStringHandle( basepath );
|
||||
//handle.file = m_StringPool.ReferenceStringHandle( filename );
|
||||
m_lock.UnlockWrite();
|
||||
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName )
|
||||
{
|
||||
if ( !pFileName )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fix slashes+dotslashes and make lower case first..
|
||||
char fn[ MAX_PATH ];
|
||||
Q_strncpy( fn, pFileName, sizeof( fn ) );
|
||||
Q_RemoveDotSlashes( fn );
|
||||
#ifdef _WIN32
|
||||
Q_strlower( fn );
|
||||
#endif
|
||||
|
||||
// Split the filename into constituent parts
|
||||
char basepath[ MAX_PATH ];
|
||||
Q_ExtractFilePath( fn, basepath, sizeof( basepath ) );
|
||||
char filename[ MAX_PATH ];
|
||||
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
|
||||
|
||||
FileNameHandleInternal_t handle;
|
||||
|
||||
Assert( (uint16)(m_Strings->InvalidHandle() + 1) == 0 );
|
||||
|
||||
m_lock.LockForRead();
|
||||
handle.path = m_Strings->Find(basepath) + 1;
|
||||
handle.file = m_Strings->Find(filename) + 1;
|
||||
//handle.path = m_StringPool.FindStringHandle(basepath);
|
||||
//handle.file = m_StringPool.FindStringHandle(filename);
|
||||
m_lock.UnlockRead();
|
||||
|
||||
if ( handle.path == 0 || handle.file == 0 )
|
||||
return NULL;
|
||||
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : handle -
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, int buflen )
|
||||
{
|
||||
buf[ 0 ] = 0;
|
||||
|
||||
FileNameHandleInternal_t *internal = ( FileNameHandleInternal_t * )&handle;
|
||||
if ( !internal || !internal->file || !internal->path )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock.LockForRead();
|
||||
//const char *path = m_StringPool.HandleToString(internal->path);
|
||||
//const char *fn = m_StringPool.HandleToString(internal->file);
|
||||
const char *path = (*m_Strings)[ internal->path - 1 ].Get();
|
||||
const char *fn = (*m_Strings)[ internal->file - 1].Get();
|
||||
m_lock.UnlockRead();
|
||||
|
||||
if ( !path || !fn )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_strncpy( buf, path, buflen );
|
||||
Q_strncat( buf, fn, buflen, COPY_ALL_CHARACTERS );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CUtlFilenameSymbolTable::RemoveAll()
|
||||
{
|
||||
m_Strings->Purge();
|
||||
}
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Defines a symbol table
|
||||
//
|
||||
// $Header: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#pragma warning (disable:4514)
|
||||
|
||||
#include "utlsymbol.h"
|
||||
#include "KeyValues.h"
|
||||
#include "tier0/threadtools.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
#include "stringpool.h"
|
||||
#include "utlhashtable.h"
|
||||
#include "utlstring.h"
|
||||
|
||||
// Ensure that everybody has the right compiler version installed. The version
|
||||
// number can be obtained by looking at the compiler output when you type 'cl'
|
||||
// and removing the last two digits and the periods: 16.00.40219.01 becomes 160040219
|
||||
#ifdef _MSC_FULL_VER
|
||||
#if _MSC_FULL_VER > 160000000
|
||||
// VS 2010
|
||||
#if _MSC_FULL_VER < 160040219
|
||||
#error You must install VS 2010 SP1
|
||||
#endif
|
||||
#else
|
||||
// VS 2005
|
||||
#if _MSC_FULL_VER < 140050727
|
||||
#error You must install VS 2005 SP1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define INVALID_STRING_INDEX CStringPoolIndex( 0xFFFF, 0xFFFF )
|
||||
|
||||
#define MIN_STRING_POOL_SIZE 2048
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// globals
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbolTableMT* CUtlSymbol::s_pSymbolTable = 0;
|
||||
bool CUtlSymbol::s_bAllowStaticSymbolTable = true;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// symbol methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlSymbol::Initialize()
|
||||
{
|
||||
// If this assert fails, then the module that this call is in has chosen to disallow
|
||||
// use of the static symbol table. Usually, it's to prevent confusion because it's easy
|
||||
// to accidentally use the global symbol table when you really want to use a specific one.
|
||||
Assert( s_bAllowStaticSymbolTable );
|
||||
|
||||
// necessary to allow us to create global symbols
|
||||
static bool symbolsInitialized = false;
|
||||
if (!symbolsInitialized)
|
||||
{
|
||||
s_pSymbolTable = new CUtlSymbolTableMT;
|
||||
symbolsInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Singleton to delete table on exit from module
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCleanupUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
~CCleanupUtlSymbolTable()
|
||||
{
|
||||
delete CUtlSymbol::s_pSymbolTable;
|
||||
CUtlSymbol::s_pSymbolTable = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static CCleanupUtlSymbolTable g_CleanupSymbolTable;
|
||||
|
||||
CUtlSymbolTableMT* CUtlSymbol::CurrTable()
|
||||
{
|
||||
Initialize();
|
||||
return s_pSymbolTable;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// string->symbol->string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbol::CUtlSymbol( const char* pStr )
|
||||
{
|
||||
m_Id = CurrTable()->AddString( pStr );
|
||||
}
|
||||
|
||||
const char* CUtlSymbol::String( ) const
|
||||
{
|
||||
return CurrTable()->String(m_Id);
|
||||
}
|
||||
|
||||
void CUtlSymbol::DisableStaticSymbolTable()
|
||||
{
|
||||
s_bAllowStaticSymbolTable = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// checks if the symbol matches a string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool CUtlSymbol::operator==( const char* pStr ) const
|
||||
{
|
||||
if (m_Id == UTL_INVAL_SYMBOL)
|
||||
return false;
|
||||
return strcmp( String(), pStr ) == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// symbol table stuff
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const
|
||||
{
|
||||
Assert( index.m_iPool < m_StringPools.Count() );
|
||||
Assert( index.m_iOffset < m_StringPools[index.m_iPool]->m_TotalLen );
|
||||
|
||||
return &m_StringPools[index.m_iPool]->m_Data[index.m_iOffset];
|
||||
}
|
||||
|
||||
|
||||
bool CUtlSymbolTable::CLess::operator()( const CStringPoolIndex &i1, const CStringPoolIndex &i2 ) const
|
||||
{
|
||||
// Need to do pointer math because CUtlSymbolTable is used in CUtlVectors, and hence
|
||||
// can be arbitrarily moved in memory on a realloc. Yes, this is portable. In reality,
|
||||
// right now at least, because m_LessFunc is the first member of CUtlRBTree, and m_Lookup
|
||||
// is the first member of CUtlSymbolTabke, this == pTable
|
||||
CUtlSymbolTable *pTable = (CUtlSymbolTable *)( (byte *)this - offsetof(CUtlSymbolTable::CTree, m_LessFunc) ) - offsetof(CUtlSymbolTable, m_Lookup );
|
||||
const char* str1 = (i1 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
|
||||
pTable->StringFromIndex( i1 );
|
||||
const char* str2 = (i2 == INVALID_STRING_INDEX) ? pTable->m_pUserSearchString :
|
||||
pTable->StringFromIndex( i2 );
|
||||
|
||||
if ( !str1 && str2 )
|
||||
return false;
|
||||
if ( !str2 && str1 )
|
||||
return true;
|
||||
if ( !str1 && !str2 )
|
||||
return false;
|
||||
if ( !pTable->m_bInsensitive )
|
||||
return V_strcmp( str1, str2 ) < 0;
|
||||
else
|
||||
return V_stricmp( str1, str2 ) < 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlSymbolTable::CUtlSymbolTable( int growSize, int initSize, bool caseInsensitive ) :
|
||||
m_Lookup( growSize, initSize ), m_bInsensitive( caseInsensitive ), m_StringPools( 8 )
|
||||
{
|
||||
}
|
||||
|
||||
CUtlSymbolTable::~CUtlSymbolTable()
|
||||
{
|
||||
// Release the stringpool string data
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
CUtlSymbol CUtlSymbolTable::Find( const char* pString ) const
|
||||
{
|
||||
if (!pString)
|
||||
return CUtlSymbol();
|
||||
|
||||
// Store a special context used to help with insertion
|
||||
m_pUserSearchString = pString;
|
||||
|
||||
// Passing this special invalid symbol makes the comparison function
|
||||
// use the string passed in the context
|
||||
UtlSymId_t idx = m_Lookup.Find( INVALID_STRING_INDEX );
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_pUserSearchString = NULL;
|
||||
#endif
|
||||
|
||||
return CUtlSymbol( idx );
|
||||
}
|
||||
|
||||
|
||||
int CUtlSymbolTable::FindPoolWithSpace( int len ) const
|
||||
{
|
||||
for ( int i=0; i < m_StringPools.Count(); i++ )
|
||||
{
|
||||
StringPool_t *pPool = m_StringPools[i];
|
||||
|
||||
if ( (pPool->m_TotalLen - pPool->m_SpaceUsed) >= len )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds and/or creates a symbol based on the string
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CUtlSymbol CUtlSymbolTable::AddString( const char* pString )
|
||||
{
|
||||
if (!pString)
|
||||
return CUtlSymbol( UTL_INVAL_SYMBOL );
|
||||
|
||||
CUtlSymbol id = Find( pString );
|
||||
|
||||
if (id.IsValid())
|
||||
return id;
|
||||
|
||||
int len = strlen(pString) + 1;
|
||||
|
||||
// Find a pool with space for this string, or allocate a new one.
|
||||
int iPool = FindPoolWithSpace( len );
|
||||
if ( iPool == -1 )
|
||||
{
|
||||
// Add a new pool.
|
||||
int newPoolSize = max( len, MIN_STRING_POOL_SIZE );
|
||||
StringPool_t *pPool = (StringPool_t*)malloc( sizeof( StringPool_t ) + newPoolSize - 1 );
|
||||
pPool->m_TotalLen = newPoolSize;
|
||||
pPool->m_SpaceUsed = 0;
|
||||
iPool = m_StringPools.AddToTail( pPool );
|
||||
}
|
||||
|
||||
// Copy the string in.
|
||||
StringPool_t *pPool = m_StringPools[iPool];
|
||||
Assert( pPool->m_SpaceUsed < 0xFFFF ); // This should never happen, because if we had a string > 64k, it
|
||||
// would have been given its entire own pool.
|
||||
|
||||
unsigned short iStringOffset = pPool->m_SpaceUsed;
|
||||
|
||||
memcpy( &pPool->m_Data[pPool->m_SpaceUsed], pString, len );
|
||||
pPool->m_SpaceUsed += len;
|
||||
|
||||
// didn't find, insert the string into the vector.
|
||||
CStringPoolIndex index;
|
||||
index.m_iPool = iPool;
|
||||
index.m_iOffset = iStringOffset;
|
||||
|
||||
UtlSymId_t idx = m_Lookup.Insert( index );
|
||||
return CUtlSymbol( idx );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Look up the string associated with a particular symbol
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const char* CUtlSymbolTable::String( CUtlSymbol id ) const
|
||||
{
|
||||
if (!id.IsValid())
|
||||
return "";
|
||||
|
||||
Assert( m_Lookup.IsValidIndex((UtlSymId_t)id) );
|
||||
return StringFromIndex( m_Lookup[id] );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Remove all symbols in the table.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlSymbolTable::RemoveAll()
|
||||
{
|
||||
m_Lookup.Purge();
|
||||
|
||||
for ( int i=0; i < m_StringPools.Count(); i++ )
|
||||
free( m_StringPools[i] );
|
||||
|
||||
m_StringPools.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CUtlFilenameSymbolTable::HashTable : public CUtlStableHashtable<CUtlConstString>
|
||||
{
|
||||
};
|
||||
|
||||
CUtlFilenameSymbolTable::CUtlFilenameSymbolTable()
|
||||
{
|
||||
m_Strings = new HashTable;
|
||||
}
|
||||
|
||||
CUtlFilenameSymbolTable::~CUtlFilenameSymbolTable()
|
||||
{
|
||||
delete m_Strings;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pFileName -
|
||||
// Output : FileNameHandle_t
|
||||
//-----------------------------------------------------------------------------
|
||||
FileNameHandle_t CUtlFilenameSymbolTable::FindOrAddFileName( const char *pFileName )
|
||||
{
|
||||
if ( !pFileName )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find first
|
||||
FileNameHandle_t hFileName = FindFileName( pFileName );
|
||||
if ( hFileName )
|
||||
{
|
||||
return hFileName;
|
||||
}
|
||||
|
||||
// Fix slashes+dotslashes and make lower case first..
|
||||
char fn[ MAX_PATH ];
|
||||
Q_strncpy( fn, pFileName, sizeof( fn ) );
|
||||
Q_RemoveDotSlashes( fn );
|
||||
#ifdef _WIN32
|
||||
Q_strlower( fn );
|
||||
#endif
|
||||
|
||||
// Split the filename into constituent parts
|
||||
char basepath[ MAX_PATH ];
|
||||
Q_ExtractFilePath( fn, basepath, sizeof( basepath ) );
|
||||
char filename[ MAX_PATH ];
|
||||
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
|
||||
|
||||
// not found, lock and look again
|
||||
FileNameHandleInternal_t handle;
|
||||
m_lock.LockForWrite();
|
||||
handle.path = m_Strings->Insert( basepath ) + 1;
|
||||
handle.file = m_Strings->Insert( filename ) + 1;
|
||||
//handle.path = m_StringPool.FindStringHandle( basepath );
|
||||
//handle.file = m_StringPool.FindStringHandle( filename );
|
||||
//if ( handle.path != m_Strings.InvalidHandle() && handle.file )
|
||||
//{
|
||||
// found
|
||||
// m_lock.UnlockWrite();
|
||||
// return *( FileNameHandle_t * )( &handle );
|
||||
//}
|
||||
|
||||
// safely add it
|
||||
//handle.path = m_StringPool.ReferenceStringHandle( basepath );
|
||||
//handle.file = m_StringPool.ReferenceStringHandle( filename );
|
||||
m_lock.UnlockWrite();
|
||||
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName )
|
||||
{
|
||||
if ( !pFileName )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fix slashes+dotslashes and make lower case first..
|
||||
char fn[ MAX_PATH ];
|
||||
Q_strncpy( fn, pFileName, sizeof( fn ) );
|
||||
Q_RemoveDotSlashes( fn );
|
||||
#ifdef _WIN32
|
||||
Q_strlower( fn );
|
||||
#endif
|
||||
|
||||
// Split the filename into constituent parts
|
||||
char basepath[ MAX_PATH ];
|
||||
Q_ExtractFilePath( fn, basepath, sizeof( basepath ) );
|
||||
char filename[ MAX_PATH ];
|
||||
Q_strncpy( filename, fn + Q_strlen( basepath ), sizeof( filename ) );
|
||||
|
||||
FileNameHandleInternal_t handle;
|
||||
|
||||
Assert( (uint16)(m_Strings->InvalidHandle() + 1) == 0 );
|
||||
|
||||
m_lock.LockForRead();
|
||||
handle.path = m_Strings->Find(basepath) + 1;
|
||||
handle.file = m_Strings->Find(filename) + 1;
|
||||
//handle.path = m_StringPool.FindStringHandle(basepath);
|
||||
//handle.file = m_StringPool.FindStringHandle(filename);
|
||||
m_lock.UnlockRead();
|
||||
|
||||
if ( handle.path == 0 || handle.file == 0 )
|
||||
return NULL;
|
||||
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : handle -
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, int buflen )
|
||||
{
|
||||
buf[ 0 ] = 0;
|
||||
|
||||
FileNameHandleInternal_t *internal = ( FileNameHandleInternal_t * )&handle;
|
||||
if ( !internal || !internal->file || !internal->path )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock.LockForRead();
|
||||
//const char *path = m_StringPool.HandleToString(internal->path);
|
||||
//const char *fn = m_StringPool.HandleToString(internal->file);
|
||||
const char *path = (*m_Strings)[ internal->path - 1 ].Get();
|
||||
const char *fn = (*m_Strings)[ internal->file - 1].Get();
|
||||
m_lock.UnlockRead();
|
||||
|
||||
if ( !path || !fn )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_strncpy( buf, path, buflen );
|
||||
Q_strncat( buf, fn, buflen, COPY_ALL_CHARACTERS );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CUtlFilenameSymbolTable::RemoveAll()
|
||||
{
|
||||
m_Strings->Purge();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user