initial
This commit is contained in:
378
tier1/NetAdr.cpp
Normal file
378
tier1/NetAdr.cpp
Normal file
@@ -0,0 +1,378 @@
|
||||
//===== Copyright <20> 1996-2005, 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 onlyBase ) const
|
||||
{
|
||||
// Select a static buffer
|
||||
static char s[4][64];
|
||||
static int slot = 0;
|
||||
int useSlot = ( slot++ ) % 4;
|
||||
|
||||
// Render into it
|
||||
ToString( s[useSlot], sizeof(s[0]), onlyBase );
|
||||
|
||||
// Pray the caller uses it before it gets clobbered
|
||||
return s[useSlot];
|
||||
}
|
||||
|
||||
void netadr_t::ToString( char *pchBuffer, uint32 unBufferSize, bool onlyBase ) const
|
||||
{
|
||||
|
||||
if (type == NA_LOOPBACK)
|
||||
{
|
||||
V_strncpy( pchBuffer, "loopback", unBufferSize );
|
||||
}
|
||||
else if (type == NA_BROADCAST)
|
||||
{
|
||||
V_strncpy( pchBuffer, "broadcast", unBufferSize );
|
||||
}
|
||||
else if (type == NA_IP)
|
||||
{
|
||||
if ( onlyBase )
|
||||
{
|
||||
V_snprintf( pchBuffer, unBufferSize, "%i.%i.%i.%i", ip[0], ip[1], ip[2], ip[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_snprintf( pchBuffer, unBufferSize, "%i.%i.%i.%i:%i", ip[0], ip[1], ip[2], ip[3], ntohs(port));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
V_strncpy( pchBuffer, "unknown", unBufferSize );
|
||||
}
|
||||
}
|
||||
|
||||
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 BigDWord( 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 ) );
|
||||
}
|
||||
|
||||
bool netadr_t::IsBaseAdrValid() const
|
||||
{
|
||||
return ( (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 );
|
||||
}
|
||||
|
||||
bool 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 false;
|
||||
|
||||
char address[ 128 ];
|
||||
V_strcpy_safe( address, pch );
|
||||
|
||||
if ( !V_strnicmp( address, "loopback", 8 ) )
|
||||
{
|
||||
char newaddress[ 128 ];
|
||||
type = NA_LOOPBACK;
|
||||
V_strcpy_safe( newaddress, "127.0.0.1" );
|
||||
V_strcat_safe( newaddress, address + 8 ); // copy anything after "loopback"
|
||||
|
||||
V_strcpy_safe( address, newaddress );
|
||||
}
|
||||
|
||||
if ( !V_strnicmp( address, "localhost", 9 ) )
|
||||
{
|
||||
V_memcpy( address, "127.0.0.1", 9 ); // Note use of memcpy allows us to keep the colon and rest of string since localhost and 127.0.0.1 are both 9 characters.
|
||||
}
|
||||
|
||||
// Starts with a number and has a dot
|
||||
if ( address[0] >= '0' &&
|
||||
address[0] <= '9' &&
|
||||
strchr( address, '.' ) )
|
||||
{
|
||||
int n1 = -1, n2 = -1, n3 = -1, n4 = -1, n5 = 0; // set port to 0 if we don't parse one
|
||||
int nRes = sscanf( address, "%d.%d.%d.%d:%d", &n1, &n2, &n3, &n4, &n5 );
|
||||
if (
|
||||
nRes < 4
|
||||
|| n1 < 0 || n1 > 255
|
||||
|| n2 < 0 || n2 > 255
|
||||
|| n3 < 0 || n3 > 255
|
||||
|| n4 < 0 || n4 > 255
|
||||
|| n5 < 0 || n5 > 65535
|
||||
)
|
||||
return false;
|
||||
SetIP( n1, n2, n3, n4 );
|
||||
SetPort( ( uint16 ) n5 );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( bUseDNS )
|
||||
{
|
||||
// X360TBD:
|
||||
// dgoodenough - since this is skipped on X360, seems reasonable to skip as well on PS3
|
||||
// PS3_BUILDFIX
|
||||
// FIXME - Leap of faith, this works without asserting on X360, so I assume it will on PS3
|
||||
#if !defined( _X360 ) && !defined( _PS3 )
|
||||
// Null out the colon if there is one
|
||||
char *pchColon = strchr( address, ':' );
|
||||
if ( pchColon )
|
||||
{
|
||||
*pchColon = 0;
|
||||
}
|
||||
|
||||
// DNS it base name
|
||||
struct hostent *h = gethostbyname( address );
|
||||
if ( !h )
|
||||
return false;
|
||||
|
||||
SetIP( ntohl( *(int *)h->h_addr_list[0] ) );
|
||||
|
||||
// Set Port to whatever was specified after the colon
|
||||
if ( pchColon )
|
||||
{
|
||||
SetPort( V_atoi( ++pchColon ) );
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
Assert( 0 );
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
// dgoodenough - since this is skipped on X360, seems reasonable to skip as well on PS3
|
||||
// PS3_BUILDFIX
|
||||
// FIXME - Leap of faith, this works without asserting on X360, so I assume it will on PS3
|
||||
#if !defined( _X360 ) && !defined( _PS3 )
|
||||
Clear();
|
||||
type = NA_IP;
|
||||
|
||||
struct sockaddr address;
|
||||
socklen_t namelen = sizeof(address);
|
||||
if ( getsockname( hSocket, (struct sockaddr *)&address, &namelen) == 0 )
|
||||
{
|
||||
SetFromSockadr( &address );
|
||||
}
|
||||
#else
|
||||
Assert(0);
|
||||
#endif
|
||||
}
|
||||
268
tier1/_vpc_/manifest_tier1/win32/manifest.txt
Normal file
268
tier1/_vpc_/manifest_tier1/win32/manifest.txt
Normal file
@@ -0,0 +1,268 @@
|
||||
// ----------------------------------------- //
|
||||
// File generated by VPC //
|
||||
// ----------------------------------------- //
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\appinstance.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\appinstance.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\appinstance.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\bitbuf.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\bitbuf.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\bitbuf.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\byteswap.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\byteswap.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\byteswap.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\characterset.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\characterset.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\characterset.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\checksum_crc.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\checksum_crc.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\checksum_crc.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\checksum_md5.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\checksum_md5.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\checksum_md5.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\checksum_sha1.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\checksum_sha1.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\checksum_sha1.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\circularbuffer.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\circularbuffer.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\circularbuffer.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\commandbuffer.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\commandbuffer.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\commandbuffer.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\convar.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\convar.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\convar.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\datamanager.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\datamanager.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\datamanager.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\diff.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\diff.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\diff.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\exprevaluator.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\exprevaluator.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\exprevaluator.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\generichash.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\generichash.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\generichash.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\interface.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\interface.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\interface.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\keyvalues.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\keyvalues.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\keyvalues.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\keyvaluesjson.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\keyvaluesjson.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\keyvaluesjson.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\kvpacker.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\kvpacker.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\kvpacker.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\lzmaDecoder.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\lzmaDecoder.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\lzmaDecoder.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\lzss.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\lzss.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\lzss.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\memoverride_dummy.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\memoverride_dummy.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\memoverride_dummy.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\mempool.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\mempool.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\mempool.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\memstack.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\memstack.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\memstack.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\miniprofiler_hash.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\miniprofiler_hash.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\miniprofiler_hash.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\NetAdr.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\NetAdr.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\NetAdr.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\newbitbuf.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\newbitbuf.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\newbitbuf.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\processor_detect.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\processor_detect.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\processor_detect.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\rangecheckedvar.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\rangecheckedvar.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\rangecheckedvar.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\sparsematrix.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\sparsematrix.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\sparsematrix.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\splitstring.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\splitstring.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\splitstring.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\stringpool.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\stringpool.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\stringpool.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\strtools.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\strtools.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\strtools.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\strtools_unicode.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\strtools_unicode.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\strtools_unicode.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\tier1.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\tier1.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\tier1.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\tier1_logging.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\tier1_logging.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\tier1_logging.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\timeutils.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\timeutils.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\timeutils.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\uniqueid.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\uniqueid.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\uniqueid.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\utlbuffer.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\utlbuffer.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\utlbuffer.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\utlbufferutil.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\utlbufferutil.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\utlbufferutil.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\utlsoacontainer.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\utlsoacontainer.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\utlsoacontainer.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\utlstring.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\utlstring.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\utlstring.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\utlstringtoken.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\utlstringtoken.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\utlstringtoken.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\tier1\utlsymbol.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\tier1\utlsymbol.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\tier1\utlsymbol.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
248
tier1/appinstance.cpp
Normal file
248
tier1/appinstance.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
// ======= Copyright (c) 2009, Valve Corporation, All rights reserved. =========
|
||||
//
|
||||
// appinstance.cpp
|
||||
//
|
||||
// Purpose: Provide a simple way to enforce that only one instance of an
|
||||
// application is running on a machine at any one time.
|
||||
//
|
||||
// Usage: declare a global object of CSingleAppInstance type, with the unique name
|
||||
// you want to use wrapped in the TEXT( " " ) macro.
|
||||
//
|
||||
// upon entering main you can check the IsUniqueInstance() method to determine if another instance is running
|
||||
// or you can call the CheckForOtherRunningInstances() method to perform the check AND optinally
|
||||
// pop up a message box to the user, and/or have the program terminate
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// CSingleAppInstance g_ThisAppInstance( TEXT("this_source_app") );
|
||||
//
|
||||
// void main(int argc,char **argv)
|
||||
// {
|
||||
// if ( g_ThisAppInstance.CheckForOtherRunningInstances() ) return;
|
||||
//
|
||||
// .. rest of code ..
|
||||
//
|
||||
// Notes: Currently this object only works when IsPlatformWindows() is true
|
||||
// i.e. no Xbox 360, linux, or Mac yet..
|
||||
// (feel free to impliment)
|
||||
//
|
||||
// ===========================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "tier1/appinstance.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS_PC
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef PLATFORM_OSX
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "tier1/checksum_crc.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// Constructor - create a named mutex on the PC and see if someone else has
|
||||
// already done it.
|
||||
// ===========================================================================
|
||||
CSingleAppInstance::CSingleAppInstance( tchar* InstanceName, bool exitOnNotUnique, bool displayMsgIfNotUnique )
|
||||
{
|
||||
// defaults for non-Windows builds
|
||||
m_hMutex = NULL;
|
||||
m_isUniqueInstance = true;
|
||||
|
||||
if ( InstanceName == NULL || V_strlen( InstanceName ) == 0 || V_strlen( InstanceName ) >= MAX_PATH )
|
||||
{
|
||||
Assert( false );
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef _PS3
|
||||
#ifdef WIN32
|
||||
if ( IsPlatformWindows() )
|
||||
{
|
||||
// don't allow more than one instance to run
|
||||
m_hMutex = ::CreateMutex( NULL, FALSE, InstanceName );
|
||||
|
||||
unsigned int waitResult = ::WaitForSingleObject( m_hMutex, 0 );
|
||||
|
||||
// Here, we have the mutex
|
||||
if ( waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED )
|
||||
{
|
||||
m_isUniqueInstance = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// couldn't get the mutex, we must be running another instance
|
||||
::CloseHandle( m_hMutex );
|
||||
m_hMutex = NULL;
|
||||
|
||||
|
||||
// note that we are not unique, i.e. another instance of this app (or one using the same instance name) is running
|
||||
m_isUniqueInstance = false;
|
||||
|
||||
CheckForOtherRunningInstances( exitOnNotUnique, displayMsgIfNotUnique );
|
||||
}
|
||||
#elif defined(OSX)
|
||||
|
||||
m_hMutex = -1; // 0 in theory is a valid fd, so set the sentinal to -1 for checking in the destructor
|
||||
|
||||
// Under OSX use flock in /tmp/source_engine_<game>.lock, create the file if it doesn't exist
|
||||
CRC32_t gameCRC;
|
||||
CRC32_Init(&gameCRC);
|
||||
CRC32_ProcessBuffer( &gameCRC, (void *)InstanceName, Q_strlen( InstanceName ) );
|
||||
CRC32_Final( &gameCRC );
|
||||
|
||||
V_snprintf( m_szLockPath, sizeof(m_szLockPath), "/tmp/source_engine_%lu.lock", gameCRC );
|
||||
m_hMutex = open( m_szLockPath, O_CREAT | O_WRONLY | O_EXLOCK | O_NONBLOCK | O_TRUNC, 0777 );
|
||||
if( m_hMutex >= 0 )
|
||||
{
|
||||
// make sure we give full perms to the file, we only one instance per machine
|
||||
fchmod( m_hMutex, 0777 );
|
||||
|
||||
m_isUniqueInstance = true;
|
||||
// we leave the file open, under unix rules when we die we'll automatically close and remove the locks
|
||||
return;
|
||||
}
|
||||
|
||||
// We were unable to open the file, it should be because we are unable to retain a lock
|
||||
if ( errno != EWOULDBLOCK)
|
||||
{
|
||||
fprintf( stderr, "unexpected error %d trying to exclusively lock %s\n", errno, m_szLockPath );
|
||||
}
|
||||
|
||||
m_isUniqueInstance = false;
|
||||
#endif
|
||||
|
||||
#endif // _PS3
|
||||
}
|
||||
|
||||
|
||||
|
||||
CSingleAppInstance::~CSingleAppInstance()
|
||||
{
|
||||
#ifndef _PS3
|
||||
#ifdef WIN32
|
||||
if ( IsPlatformWindows() && m_hMutex )
|
||||
{
|
||||
::ReleaseMutex( m_hMutex );
|
||||
::CloseHandle( m_hMutex );
|
||||
m_hMutex = NULL;
|
||||
}
|
||||
#elif defined(OSX)
|
||||
if ( m_hMutex != -1 )
|
||||
{
|
||||
close( m_hMutex );
|
||||
m_hMutex = -1;
|
||||
unlink( m_szLockPath );
|
||||
}
|
||||
#endif
|
||||
#endif // _PS3
|
||||
}
|
||||
|
||||
|
||||
bool CSingleAppInstance::CheckForOtherRunningInstances( bool exitOnNotUnique, bool displayMsgIfNotUnique )
|
||||
{
|
||||
|
||||
if ( IsPlatformWindows() || IsOSX() )
|
||||
{
|
||||
// are we the only running instance of this app? Then we are Unique (aren't we SPECIAL?)
|
||||
if ( m_isUniqueInstance )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// should we display a message to the user?
|
||||
if ( displayMsgIfNotUnique )
|
||||
{
|
||||
Plat_MessageBox( "Alert", "Another copy of this program is already running on this machine. Only one instance at a time is allowed" );
|
||||
}
|
||||
|
||||
// should we attempt normal program termination?
|
||||
if ( exitOnNotUnique )
|
||||
{
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// We fell through, so act like there are no other instances
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===========================================================================
|
||||
// Static Function - this is used by *other* programs to query the system for
|
||||
// a running program that grabs the named mutex/has a CSingleAppInstance
|
||||
// object of the specified name.
|
||||
// It's a way to check if a tool is running or not, (and then presumably
|
||||
// lauch it if it is not there).
|
||||
// ===========================================================================
|
||||
bool CSingleAppInstance::CheckForRunningInstance( tchar* InstanceName )
|
||||
{
|
||||
#ifndef _PS3
|
||||
// validate input
|
||||
Assert( InstanceName != NULL && V_strlen( InstanceName ) > 0 && V_strlen( InstanceName ) < MAX_PATH );
|
||||
|
||||
#ifdef WIN32
|
||||
if ( IsPlatformWindows() )
|
||||
{
|
||||
// don't allow more than one instance to run
|
||||
HANDLE hMutex = ::CreateMutex( NULL, FALSE, InstanceName );
|
||||
|
||||
unsigned int waitResult = ::WaitForSingleObject( hMutex, 0 );
|
||||
|
||||
::CloseHandle( hMutex );
|
||||
|
||||
// Did we grab the mutex successfully? nope...
|
||||
if ( waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// couldn't get the mutex, must be another instance running somewhere that has it
|
||||
return true;
|
||||
|
||||
}
|
||||
#elif defined(OSX)
|
||||
// Under OSX use flock in /tmp/source_engine_<game>.lock, create the file if it doesn't exist
|
||||
CRC32_t gameCRC;
|
||||
CRC32_Init(&gameCRC);
|
||||
CRC32_ProcessBuffer( &gameCRC, (void *)InstanceName, Q_strlen( InstanceName ) );
|
||||
CRC32_Final( &gameCRC );
|
||||
|
||||
char szLockPath[ MAX_PATH ];
|
||||
V_snprintf( szLockPath, sizeof(szLockPath), "/tmp/source_engine_%lu.lock", gameCRC );
|
||||
int lockFD = open( szLockPath, O_CREAT | O_WRONLY | O_EXLOCK | O_NONBLOCK | O_TRUNC, 0777 );
|
||||
if( lockFD >= 0 )
|
||||
{
|
||||
close( lockFD );
|
||||
unlink( szLockPath );
|
||||
return false;
|
||||
}
|
||||
|
||||
// We were unable to open the file, it should be because we are unable to retain a lock
|
||||
if ( errno != EWOULDBLOCK)
|
||||
{
|
||||
fprintf( stderr, "unexpected error %d trying to exclusively lock %s\n", errno, szLockPath );
|
||||
}
|
||||
|
||||
// couldn't get the mutex, must be another instance running somewhere that has it
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#endif // _PS3
|
||||
|
||||
return false;
|
||||
}
|
||||
1626
tier1/bitbuf.cpp
Normal file
1626
tier1/bitbuf.cpp
Normal file
File diff suppressed because it is too large
Load Diff
102
tier1/byteswap.cpp
Normal file
102
tier1/byteswap.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
//========= Copyright © 1996-2006, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Low level byte swapping routines.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#include "byteswap.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.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_COLOR32:
|
||||
SwapBufferToTargetEndian<char>( (char*)pOutputBuffer, (char*)pData, pField->fieldSize * 4 );
|
||||
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_INTEGER64:
|
||||
SwapBufferToTargetEndian<uint64>( (uint64*)pOutputBuffer, (uint64*)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,
|
||||
(byte*)pData + pEmbed->fieldOffset,
|
||||
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,
|
||||
(BYTE*)pBaseData + pField->fieldOffset,
|
||||
pField );
|
||||
}
|
||||
}
|
||||
|
||||
41
tier1/characterset.cpp
Normal file
41
tier1/characterset.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
//========= Copyright © 1996-2005, 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++;
|
||||
}
|
||||
|
||||
}
|
||||
302
tier1/checksum_crc.cpp
Normal file
302
tier1/checksum_crc.cpp
Normal file
@@ -0,0 +1,302 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Generic CRC functions
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "commonmacros.h"
|
||||
#include "tier1/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 = ((uintp)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;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CRC64
|
||||
//-----------------------------------------------------------------------------
|
||||
#define CRC64_INIT_VALUE 0xFFFFFFFFFFFFFFFFULL
|
||||
#define CRC64_XOR_VALUE 0xFFFFFFFFFFFFFFFFULL
|
||||
|
||||
#define NUM_CRC64_TABLE_ENTRIES 256
|
||||
static const CRC64_t pCRC64Table[ NUM_CRC64_TABLE_ENTRIES ] =
|
||||
{
|
||||
/*
|
||||
// Uncomment this to generate and print this table.
|
||||
// The value 0x95AC9329AC4BC9B5ULL comes from "An Improved 64-bit Cyclic Redundancy Check for Protein Sequences" David T. Jones
|
||||
for ( int i = 0; i < 256; i++ )
|
||||
{
|
||||
CRC64_t part = i;
|
||||
for (int b = 0; b < 8; b++)
|
||||
{
|
||||
if (part & 1)
|
||||
part = (part >> 1) ^ 0x95AC9329AC4BC9B5ULL;
|
||||
else
|
||||
part >>= 1;
|
||||
}
|
||||
|
||||
if ( i % 4 == 0 )
|
||||
Msg( "\n" );
|
||||
|
||||
Msg( "0x%016llXULL, ", part );
|
||||
}
|
||||
*/
|
||||
0x0000000000000000ULL, 0x7AD870C830358979ULL, 0xF5B0E190606B12F2ULL, 0x8F689158505E9B8BULL,
|
||||
0xC038E5739841B68FULL, 0xBAE095BBA8743FF6ULL, 0x358804E3F82AA47DULL, 0x4F50742BC81F2D04ULL,
|
||||
0xAB28ECB46814FE75ULL, 0xD1F09C7C5821770CULL, 0x5E980D24087FEC87ULL, 0x24407DEC384A65FEULL,
|
||||
0x6B1009C7F05548FAULL, 0x11C8790FC060C183ULL, 0x9EA0E857903E5A08ULL, 0xE478989FA00BD371ULL,
|
||||
0x7D08FF3B88BE6F81ULL, 0x07D08FF3B88BE6F8ULL, 0x88B81EABE8D57D73ULL, 0xF2606E63D8E0F40AULL,
|
||||
0xBD301A4810FFD90EULL, 0xC7E86A8020CA5077ULL, 0x4880FBD87094CBFCULL, 0x32588B1040A14285ULL,
|
||||
0xD620138FE0AA91F4ULL, 0xACF86347D09F188DULL, 0x2390F21F80C18306ULL, 0x594882D7B0F40A7FULL,
|
||||
0x1618F6FC78EB277BULL, 0x6CC0863448DEAE02ULL, 0xE3A8176C18803589ULL, 0x997067A428B5BCF0ULL,
|
||||
0xFA11FE77117CDF02ULL, 0x80C98EBF2149567BULL, 0x0FA11FE77117CDF0ULL, 0x75796F2F41224489ULL,
|
||||
0x3A291B04893D698DULL, 0x40F16BCCB908E0F4ULL, 0xCF99FA94E9567B7FULL, 0xB5418A5CD963F206ULL,
|
||||
0x513912C379682177ULL, 0x2BE1620B495DA80EULL, 0xA489F35319033385ULL, 0xDE51839B2936BAFCULL,
|
||||
0x9101F7B0E12997F8ULL, 0xEBD98778D11C1E81ULL, 0x64B116208142850AULL, 0x1E6966E8B1770C73ULL,
|
||||
0x8719014C99C2B083ULL, 0xFDC17184A9F739FAULL, 0x72A9E0DCF9A9A271ULL, 0x08719014C99C2B08ULL,
|
||||
0x4721E43F0183060CULL, 0x3DF994F731B68F75ULL, 0xB29105AF61E814FEULL, 0xC849756751DD9D87ULL,
|
||||
0x2C31EDF8F1D64EF6ULL, 0x56E99D30C1E3C78FULL, 0xD9810C6891BD5C04ULL, 0xA3597CA0A188D57DULL,
|
||||
0xEC09088B6997F879ULL, 0x96D1784359A27100ULL, 0x19B9E91B09FCEA8BULL, 0x636199D339C963F2ULL,
|
||||
0xDF7ADABD7A6E2D6FULL, 0xA5A2AA754A5BA416ULL, 0x2ACA3B2D1A053F9DULL, 0x50124BE52A30B6E4ULL,
|
||||
0x1F423FCEE22F9BE0ULL, 0x659A4F06D21A1299ULL, 0xEAF2DE5E82448912ULL, 0x902AAE96B271006BULL,
|
||||
0x74523609127AD31AULL, 0x0E8A46C1224F5A63ULL, 0x81E2D7997211C1E8ULL, 0xFB3AA75142244891ULL,
|
||||
0xB46AD37A8A3B6595ULL, 0xCEB2A3B2BA0EECECULL, 0x41DA32EAEA507767ULL, 0x3B024222DA65FE1EULL,
|
||||
0xA2722586F2D042EEULL, 0xD8AA554EC2E5CB97ULL, 0x57C2C41692BB501CULL, 0x2D1AB4DEA28ED965ULL,
|
||||
0x624AC0F56A91F461ULL, 0x1892B03D5AA47D18ULL, 0x97FA21650AFAE693ULL, 0xED2251AD3ACF6FEAULL,
|
||||
0x095AC9329AC4BC9BULL, 0x7382B9FAAAF135E2ULL, 0xFCEA28A2FAAFAE69ULL, 0x8632586ACA9A2710ULL,
|
||||
0xC9622C4102850A14ULL, 0xB3BA5C8932B0836DULL, 0x3CD2CDD162EE18E6ULL, 0x460ABD1952DB919FULL,
|
||||
0x256B24CA6B12F26DULL, 0x5FB354025B277B14ULL, 0xD0DBC55A0B79E09FULL, 0xAA03B5923B4C69E6ULL,
|
||||
0xE553C1B9F35344E2ULL, 0x9F8BB171C366CD9BULL, 0x10E3202993385610ULL, 0x6A3B50E1A30DDF69ULL,
|
||||
0x8E43C87E03060C18ULL, 0xF49BB8B633338561ULL, 0x7BF329EE636D1EEAULL, 0x012B592653589793ULL,
|
||||
0x4E7B2D0D9B47BA97ULL, 0x34A35DC5AB7233EEULL, 0xBBCBCC9DFB2CA865ULL, 0xC113BC55CB19211CULL,
|
||||
0x5863DBF1E3AC9DECULL, 0x22BBAB39D3991495ULL, 0xADD33A6183C78F1EULL, 0xD70B4AA9B3F20667ULL,
|
||||
0x985B3E827BED2B63ULL, 0xE2834E4A4BD8A21AULL, 0x6DEBDF121B863991ULL, 0x1733AFDA2BB3B0E8ULL,
|
||||
0xF34B37458BB86399ULL, 0x8993478DBB8DEAE0ULL, 0x06FBD6D5EBD3716BULL, 0x7C23A61DDBE6F812ULL,
|
||||
0x3373D23613F9D516ULL, 0x49ABA2FE23CC5C6FULL, 0xC6C333A67392C7E4ULL, 0xBC1B436E43A74E9DULL,
|
||||
0x95AC9329AC4BC9B5ULL, 0xEF74E3E19C7E40CCULL, 0x601C72B9CC20DB47ULL, 0x1AC40271FC15523EULL,
|
||||
0x5594765A340A7F3AULL, 0x2F4C0692043FF643ULL, 0xA02497CA54616DC8ULL, 0xDAFCE7026454E4B1ULL,
|
||||
0x3E847F9DC45F37C0ULL, 0x445C0F55F46ABEB9ULL, 0xCB349E0DA4342532ULL, 0xB1ECEEC59401AC4BULL,
|
||||
0xFEBC9AEE5C1E814FULL, 0x8464EA266C2B0836ULL, 0x0B0C7B7E3C7593BDULL, 0x71D40BB60C401AC4ULL,
|
||||
0xE8A46C1224F5A634ULL, 0x927C1CDA14C02F4DULL, 0x1D148D82449EB4C6ULL, 0x67CCFD4A74AB3DBFULL,
|
||||
0x289C8961BCB410BBULL, 0x5244F9A98C8199C2ULL, 0xDD2C68F1DCDF0249ULL, 0xA7F41839ECEA8B30ULL,
|
||||
0x438C80A64CE15841ULL, 0x3954F06E7CD4D138ULL, 0xB63C61362C8A4AB3ULL, 0xCCE411FE1CBFC3CAULL,
|
||||
0x83B465D5D4A0EECEULL, 0xF96C151DE49567B7ULL, 0x76048445B4CBFC3CULL, 0x0CDCF48D84FE7545ULL,
|
||||
0x6FBD6D5EBD3716B7ULL, 0x15651D968D029FCEULL, 0x9A0D8CCEDD5C0445ULL, 0xE0D5FC06ED698D3CULL,
|
||||
0xAF85882D2576A038ULL, 0xD55DF8E515432941ULL, 0x5A3569BD451DB2CAULL, 0x20ED197575283BB3ULL,
|
||||
0xC49581EAD523E8C2ULL, 0xBE4DF122E51661BBULL, 0x3125607AB548FA30ULL, 0x4BFD10B2857D7349ULL,
|
||||
0x04AD64994D625E4DULL, 0x7E7514517D57D734ULL, 0xF11D85092D094CBFULL, 0x8BC5F5C11D3CC5C6ULL,
|
||||
0x12B5926535897936ULL, 0x686DE2AD05BCF04FULL, 0xE70573F555E26BC4ULL, 0x9DDD033D65D7E2BDULL,
|
||||
0xD28D7716ADC8CFB9ULL, 0xA85507DE9DFD46C0ULL, 0x273D9686CDA3DD4BULL, 0x5DE5E64EFD965432ULL,
|
||||
0xB99D7ED15D9D8743ULL, 0xC3450E196DA80E3AULL, 0x4C2D9F413DF695B1ULL, 0x36F5EF890DC31CC8ULL,
|
||||
0x79A59BA2C5DC31CCULL, 0x037DEB6AF5E9B8B5ULL, 0x8C157A32A5B7233EULL, 0xF6CD0AFA9582AA47ULL,
|
||||
0x4AD64994D625E4DAULL, 0x300E395CE6106DA3ULL, 0xBF66A804B64EF628ULL, 0xC5BED8CC867B7F51ULL,
|
||||
0x8AEEACE74E645255ULL, 0xF036DC2F7E51DB2CULL, 0x7F5E4D772E0F40A7ULL, 0x05863DBF1E3AC9DEULL,
|
||||
0xE1FEA520BE311AAFULL, 0x9B26D5E88E0493D6ULL, 0x144E44B0DE5A085DULL, 0x6E963478EE6F8124ULL,
|
||||
0x21C640532670AC20ULL, 0x5B1E309B16452559ULL, 0xD476A1C3461BBED2ULL, 0xAEAED10B762E37ABULL,
|
||||
0x37DEB6AF5E9B8B5BULL, 0x4D06C6676EAE0222ULL, 0xC26E573F3EF099A9ULL, 0xB8B627F70EC510D0ULL,
|
||||
0xF7E653DCC6DA3DD4ULL, 0x8D3E2314F6EFB4ADULL, 0x0256B24CA6B12F26ULL, 0x788EC2849684A65FULL,
|
||||
0x9CF65A1B368F752EULL, 0xE62E2AD306BAFC57ULL, 0x6946BB8B56E467DCULL, 0x139ECB4366D1EEA5ULL,
|
||||
0x5CCEBF68AECEC3A1ULL, 0x2616CFA09EFB4AD8ULL, 0xA97E5EF8CEA5D153ULL, 0xD3A62E30FE90582AULL,
|
||||
0xB0C7B7E3C7593BD8ULL, 0xCA1FC72BF76CB2A1ULL, 0x45775673A732292AULL, 0x3FAF26BB9707A053ULL,
|
||||
0x70FF52905F188D57ULL, 0x0A2722586F2D042EULL, 0x854FB3003F739FA5ULL, 0xFF97C3C80F4616DCULL,
|
||||
0x1BEF5B57AF4DC5ADULL, 0x61372B9F9F784CD4ULL, 0xEE5FBAC7CF26D75FULL, 0x9487CA0FFF135E26ULL,
|
||||
0xDBD7BE24370C7322ULL, 0xA10FCEEC0739FA5BULL, 0x2E675FB4576761D0ULL, 0x54BF2F7C6752E8A9ULL,
|
||||
0xCDCF48D84FE75459ULL, 0xB71738107FD2DD20ULL, 0x387FA9482F8C46ABULL, 0x42A7D9801FB9CFD2ULL,
|
||||
0x0DF7ADABD7A6E2D6ULL, 0x772FDD63E7936BAFULL, 0xF8474C3BB7CDF024ULL, 0x829F3CF387F8795DULL,
|
||||
0x66E7A46C27F3AA2CULL, 0x1C3FD4A417C62355ULL, 0x935745FC4798B8DEULL, 0xE98F353477AD31A7ULL,
|
||||
0xA6DF411FBFB21CA3ULL, 0xDC0731D78F8795DAULL, 0x536FA08FDFD90E51ULL, 0x29B7D047EFEC8728ULL
|
||||
};
|
||||
|
||||
void CRC64_Init( CRC64_t *pCRC )
|
||||
{
|
||||
*pCRC = CRC64_INIT_VALUE;
|
||||
}
|
||||
|
||||
void CRC64_ProcessBuffer( CRC64_t *pCRC, const void *p, int len )
|
||||
{
|
||||
uint8 *pBytes = (uint8*)p;
|
||||
CRC64_t nCRC = *pCRC;
|
||||
|
||||
while ( len > 0 )
|
||||
{
|
||||
nCRC = pCRC64Table[ ( nCRC ^ (*pBytes) ) & 0xff ] ^ ( nCRC >> 8 );
|
||||
pBytes++;
|
||||
len--;
|
||||
}
|
||||
|
||||
*pCRC = nCRC;
|
||||
}
|
||||
|
||||
void CRC64_Final( CRC64_t *pCRC )
|
||||
{
|
||||
*pCRC ^= CRC64_XOR_VALUE;
|
||||
}
|
||||
325
tier1/checksum_md5.cpp
Normal file
325
tier1/checksum_md5.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
//===== Copyright 1996-2005, 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
|
||||
//-----------------------------------------------------------------------------
|
||||
#if ( PLAT_BIG_ENDIAN == 1 )
|
||||
static void MD5Transform(unsigned int buf[4], unsigned int const in_big[16])
|
||||
{
|
||||
|
||||
unsigned int in[16];
|
||||
for( int i = 0; i != 16; ++i )
|
||||
{
|
||||
in[i] = LittleDWord(in_big[i]);
|
||||
}
|
||||
#else
|
||||
static void MD5Transform(unsigned int buf[4], unsigned int const in[16])
|
||||
{
|
||||
#endif
|
||||
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] = LittleDWord( ctx->bits[0] );
|
||||
((unsigned int *) ctx->in)[15] = LittleDWord( ctx->bits[1] );
|
||||
|
||||
MD5Transform(ctx->buf, (unsigned int *) ctx->in);
|
||||
//byteReverse((unsigned char *) ctx->buf, 4);
|
||||
#if ( PLAT_BIG_ENDIAN == 1 )
|
||||
COMPILE_TIME_ASSERT( MD5_DIGEST_LENGTH == (sizeof(unsigned int) * 4) );
|
||||
((unsigned int *)digest)[0] = LittleDWord( ctx->buf[0] );
|
||||
((unsigned int *)digest)[1] = LittleDWord( ctx->buf[1] );
|
||||
((unsigned int *)digest)[2] = LittleDWord( ctx->buf[2] );
|
||||
((unsigned int *)digest)[3] = LittleDWord( ctx->buf[3] );
|
||||
#else
|
||||
memcpy(digest, ctx->buf, MD5_DIGEST_LENGTH);
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
nSeed = LittleDWord( 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 LittleDWord(*(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 );
|
||||
}
|
||||
300
tier1/checksum_sha1.cpp
Normal file
300
tier1/checksum_sha1.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
//========= Copyright © 2005, Valve Inc, 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(uint32 state[5], const uint8 buffer[64])
|
||||
#else
|
||||
void CSHA1::Transform(uint32 state[5], const uint8 buffer[64])
|
||||
#endif
|
||||
{
|
||||
uint32 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( const void *pvData, unsigned int len )
|
||||
#else
|
||||
void CSHA1::Update( const void *pvData, unsigned int len)
|
||||
#endif
|
||||
{
|
||||
const uint8 *data = (const uint8 *)pvData;
|
||||
uint32 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(const char *szFileName)
|
||||
{
|
||||
uint32 ulFileSize = 0, ulRest = 0, ulBlocks = 0;
|
||||
uint32 i = 0;
|
||||
uint8 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
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint8 finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
finalcount[i] = (uint8)((m_count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
|
||||
|
||||
Update((uint8 *)"\200", 1);
|
||||
|
||||
while ((m_count[0] & 504) != 448)
|
||||
Update((uint8 *)"\0", 1);
|
||||
|
||||
Update(finalcount, 8); // Cause a SHA1Transform()
|
||||
|
||||
for (i = 0; i < k_cubHash; i++)
|
||||
{
|
||||
m_digest[i] = (uint8)((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, uint8 uReportType)
|
||||
{
|
||||
uint8 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(uint8 *uDest)
|
||||
#else
|
||||
void CSHA1::GetHash(uint8 *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
|
||||
307
tier1/circularbuffer.cpp
Normal file
307
tier1/circularbuffer.cpp
Normal file
@@ -0,0 +1,307 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Circular Buffer
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/mempool.h"
|
||||
#include "circularbuffer.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
CCircularBuffer::CCircularBuffer()
|
||||
{
|
||||
SetSize( 0 );
|
||||
}
|
||||
|
||||
CCircularBuffer::CCircularBuffer(int size)
|
||||
{
|
||||
SetSize(size);
|
||||
}
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Sets the maximum size for a circular buffer. This does not do any
|
||||
// memory allocation, it simply informs the buffer of its size.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
void CCircularBuffer::SetSize(int size)
|
||||
{
|
||||
Assert( this );
|
||||
|
||||
m_nSize = size;
|
||||
m_nRead = 0;
|
||||
m_nWrite = 0;
|
||||
m_nCount = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Empties a circular buffer.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
void CCircularBuffer::Flush()
|
||||
{
|
||||
AssertValid();
|
||||
|
||||
m_nRead = 0;
|
||||
m_nWrite = 0;
|
||||
m_nCount = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Returns the available space in a circular buffer.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
int CCircularBuffer::GetWriteAvailable()
|
||||
{
|
||||
AssertValid();
|
||||
|
||||
return(m_nSize - m_nCount);
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Returns the size of a circular buffer.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
int CCircularBuffer::GetSize()
|
||||
{
|
||||
AssertValid();
|
||||
|
||||
return(m_nSize);
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Returns the number of bytes in a circular buffer.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
int CCircularBuffer::GetReadAvailable()
|
||||
{
|
||||
AssertValid();
|
||||
|
||||
return(m_nCount);
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Reads a specified number of bytes from a circular buffer without
|
||||
// consuming them. They will still be available for future calls to
|
||||
// Read or Peek.
|
||||
//Input : pchDest - destination buffer.
|
||||
// m_nCount - number of bytes to place in destination buffer.
|
||||
//Output : Returns the number of bytes placed in the destination buffer.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
int CCircularBuffer::Peek(char *pchDest, int nCount)
|
||||
{
|
||||
// If no data available, just return.
|
||||
if(m_nCount == 0)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
//
|
||||
// Requested amount should not exceed the available amount.
|
||||
//
|
||||
nCount = MIN(m_nCount, nCount);
|
||||
|
||||
//
|
||||
// Copy as many of the requested bytes as possible.
|
||||
// If buffer wrap occurs split the data into two chunks.
|
||||
//
|
||||
if (m_nRead + nCount > m_nSize)
|
||||
{
|
||||
int nCount1 = m_nSize - m_nRead;
|
||||
memcpy(pchDest, &m_chData[m_nRead], nCount1);
|
||||
pchDest += nCount1;
|
||||
|
||||
int nCount2 = nCount - nCount1;
|
||||
memcpy(pchDest, m_chData, nCount2);
|
||||
}
|
||||
// Otherwise copy it in one go.
|
||||
else
|
||||
{
|
||||
memcpy(pchDest, &m_chData[m_nRead], nCount);
|
||||
}
|
||||
|
||||
AssertValid();
|
||||
return nCount;
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Advances the read index, consuming a specified number of bytes from
|
||||
// the circular buffer.
|
||||
//Input : m_nCount - number of bytes to consume.
|
||||
//Output : Returns the actual number of bytes consumed.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
int CCircularBuffer::Advance(int nCount)
|
||||
{
|
||||
// If no data available, just return.
|
||||
if (m_nCount == 0)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
//
|
||||
// Requested amount should not exceed the available amount.
|
||||
//
|
||||
nCount = MIN(m_nCount, nCount);
|
||||
|
||||
//
|
||||
// Advance the read pointer, checking for buffer wrap.
|
||||
//
|
||||
m_nRead = (m_nRead + nCount) % m_nSize;
|
||||
m_nCount -= nCount;
|
||||
|
||||
//
|
||||
// If we have emptied the buffer, reset the read and write indices
|
||||
// to minimize buffer wrap.
|
||||
//
|
||||
if (m_nCount == 0)
|
||||
{
|
||||
m_nRead = 0;
|
||||
m_nWrite = 0;
|
||||
}
|
||||
|
||||
AssertValid();
|
||||
return nCount;
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Reads a specified number of bytes from a circular buffer. The bytes
|
||||
// will be consumed by the read process.
|
||||
//Input : pchDest - destination buffer.
|
||||
// m_nCount - number of bytes to place in destination buffer.
|
||||
//Output : Returns the number of bytes placed in the destination buffer.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
int CCircularBuffer::Read(void *pchDestIn, int nCount)
|
||||
{
|
||||
int nPeeked;
|
||||
int m_nRead;
|
||||
|
||||
char *pchDest = (char*)pchDestIn;
|
||||
|
||||
nPeeked = Peek(pchDest, nCount);
|
||||
|
||||
if (nPeeked != 0)
|
||||
{
|
||||
m_nRead = Advance(nPeeked);
|
||||
|
||||
Assert(m_nRead == nPeeked);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nRead = 0;
|
||||
}
|
||||
|
||||
AssertValid();
|
||||
return(m_nRead);
|
||||
}
|
||||
|
||||
|
||||
//------------------ Copyright (c) 1999 Valve, LLC. ----------------------------
|
||||
//Purpose : Writes a specified number of bytes to the buffer.
|
||||
//Input : pm_chData - buffer containing bytes to bw written.
|
||||
// m_nCount - the number of bytes to write.
|
||||
//Output : Returns the number of bytes written. If there wa insufficient space
|
||||
// to write all requested bytes, the value returned will be less than
|
||||
// the requested amount.
|
||||
//Author : DSpeyrer
|
||||
//------------------------------------------------------------------------------
|
||||
int CCircularBuffer::Write(void *pData, int nBytesRequested)
|
||||
{
|
||||
// Write all the data.
|
||||
int nBytesToWrite = nBytesRequested;
|
||||
char *pDataToWrite = (char*)pData;
|
||||
|
||||
while(nBytesToWrite)
|
||||
{
|
||||
int from = m_nWrite;
|
||||
int to = m_nWrite + nBytesToWrite;
|
||||
|
||||
if(to >= m_nSize)
|
||||
{
|
||||
to = m_nSize;
|
||||
}
|
||||
|
||||
memcpy(&m_chData[from], pDataToWrite, to - from);
|
||||
pDataToWrite += to - from;
|
||||
|
||||
m_nWrite = to % m_nSize;
|
||||
nBytesToWrite -= to - from;
|
||||
}
|
||||
|
||||
// Did it cross the read pointer? Then slide the read pointer up.
|
||||
// This way, we will discard the old data.
|
||||
if(nBytesRequested > (m_nSize - m_nCount))
|
||||
{
|
||||
m_nCount = m_nSize;
|
||||
m_nRead = m_nWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nCount += nBytesRequested;
|
||||
}
|
||||
|
||||
AssertValid();
|
||||
return nBytesRequested;
|
||||
}
|
||||
|
||||
CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 8820 - 1, TSLIST_NODE_ALIGNMENT ), 24> g_SmallBuffers;
|
||||
CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 17640 - 1, TSLIST_NODE_ALIGNMENT ), 44> g_MediumBuffers;
|
||||
CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 35280 - 1, TSLIST_NODE_ALIGNMENT ), 16> g_LargeBuffers;
|
||||
|
||||
CCircularBuffer *AllocateCircularBuffer( int nSize )
|
||||
{
|
||||
CCircularBuffer *pCCircularBuffer;
|
||||
if ( nSize <= 8820 )
|
||||
{
|
||||
pCCircularBuffer = (CCircularBuffer *)g_SmallBuffers.Alloc();
|
||||
}
|
||||
else if ( nSize <= 17640 )
|
||||
{
|
||||
pCCircularBuffer = (CCircularBuffer *)g_MediumBuffers.Alloc();
|
||||
}
|
||||
else if ( nSize <= 35280 )
|
||||
{
|
||||
pCCircularBuffer = (CCircularBuffer *)g_LargeBuffers.Alloc();
|
||||
}
|
||||
else
|
||||
{
|
||||
pCCircularBuffer = (CCircularBuffer *)malloc( sizeof( CCircularBuffer ) + nSize - 1 );
|
||||
}
|
||||
|
||||
pCCircularBuffer->SetSize( nSize );
|
||||
return pCCircularBuffer;
|
||||
}
|
||||
|
||||
void FreeCircularBuffer( CCircularBuffer *pCircularBuffer )
|
||||
{
|
||||
int nSize = pCircularBuffer->GetSize();
|
||||
|
||||
if ( nSize <= 8820 )
|
||||
{
|
||||
g_SmallBuffers.Free( pCircularBuffer );
|
||||
}
|
||||
else if ( nSize <= 17640 )
|
||||
{
|
||||
g_MediumBuffers.Free( pCircularBuffer );
|
||||
}
|
||||
else if ( nSize <= 35280 )
|
||||
{
|
||||
g_LargeBuffers.Free( pCircularBuffer );
|
||||
}
|
||||
else
|
||||
{
|
||||
free( pCircularBuffer );
|
||||
}
|
||||
}
|
||||
|
||||
407
tier1/commandbuffer.cpp
Normal file
407
tier1/commandbuffer.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
//===== Copyright © 1996-2006, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier1/commandbuffer.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define MAX_ALIAS_NAME 32
|
||||
#define MAX_COMMAND_LENGTH 1024
|
||||
|
||||
struct cmdalias_t
|
||||
{
|
||||
cmdalias_t *next;
|
||||
char name[ MAX_ALIAS_NAME ];
|
||||
char *value;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CCommandBuffer::CCommandBuffer( ) : m_Commands( 32, 32 )
|
||||
{
|
||||
m_hNextCommand = m_Commands.InvalidIndex();
|
||||
m_nWaitDelayTicks = 1;
|
||||
m_nCurrentTick = 0;
|
||||
m_nLastTickToProcess = -1;
|
||||
m_nArgSBufferSize = 0;
|
||||
m_bIsProcessingCommands = false;
|
||||
m_nMaxArgSBufferLength = ARGS_BUFFER_LENGTH;
|
||||
}
|
||||
|
||||
CCommandBuffer::~CCommandBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Indicates how long to delay when encoutering a 'wait' command
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::SetWaitDelayTime( int nTickDelay )
|
||||
{
|
||||
Assert( nTickDelay >= 0 );
|
||||
m_nWaitDelayTicks = nTickDelay;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Specifies a max limit of the args buffer. For unittesting. Size == 0 means use default
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::LimitArgumentBufferSize( int nSize )
|
||||
{
|
||||
if ( nSize > ARGS_BUFFER_LENGTH )
|
||||
{
|
||||
nSize = ARGS_BUFFER_LENGTH;
|
||||
}
|
||||
|
||||
m_nMaxArgSBufferLength = ( nSize == 0 ) ? ARGS_BUFFER_LENGTH : nSize;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Parses argv0 out of the buffer
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCommandBuffer::ParseArgV0( CUtlBuffer &buf, char *pArgV0, int nMaxLen, const char **pArgS )
|
||||
{
|
||||
pArgV0[0] = 0;
|
||||
*pArgS = NULL;
|
||||
|
||||
if ( !buf.IsValid() )
|
||||
return false;
|
||||
|
||||
int nSize = buf.ParseToken( CCommand::DefaultBreakSet(), pArgV0, nMaxLen );
|
||||
if ( ( nSize <= 0 ) || ( nMaxLen == nSize ) )
|
||||
return false;
|
||||
|
||||
int nArgSLen = buf.TellMaxPut() - buf.TellGet();
|
||||
*pArgS = (nArgSLen > 0) ? (const char*)buf.PeekGet() : NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Insert a command into the command queue
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::InsertCommandAtAppropriateTime( intp hCommand )
|
||||
{
|
||||
intp i;
|
||||
Command_t &command = m_Commands[hCommand];
|
||||
for ( i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) )
|
||||
{
|
||||
if ( m_Commands[i].m_nTick > command.m_nTick )
|
||||
break;
|
||||
}
|
||||
m_Commands.LinkBefore( i, hCommand );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Insert a command into the command queue at the appropriate time
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::InsertImmediateCommand( intp hCommand )
|
||||
{
|
||||
m_Commands.LinkBefore( m_hNextCommand, hCommand );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Insert a command into the command queue
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCommandBuffer::InsertCommand( const char *pArgS, int nCommandSize, int nTick, cmd_source_t cmdSource )
|
||||
{
|
||||
if ( nCommandSize >= CCommand::MaxCommandLength() )
|
||||
{
|
||||
Warning( "WARNING: Command too long... ignoring!\n%s\n", pArgS );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add one for null termination
|
||||
if ( m_nArgSBufferSize + nCommandSize + 1 > m_nMaxArgSBufferLength )
|
||||
{
|
||||
Compact();
|
||||
if ( m_nArgSBufferSize + nCommandSize + 1 > m_nMaxArgSBufferLength )
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy( &m_pArgSBuffer[m_nArgSBufferSize], pArgS, nCommandSize );
|
||||
m_pArgSBuffer[m_nArgSBufferSize + nCommandSize] = 0;
|
||||
++nCommandSize;
|
||||
|
||||
intp hCommand = m_Commands.Alloc();
|
||||
Command_t &command = m_Commands[hCommand];
|
||||
command.m_nTick = nTick;
|
||||
command.m_nFirstArgS = m_nArgSBufferSize;
|
||||
command.m_nBufferSize = nCommandSize;
|
||||
command.m_source = cmdSource;
|
||||
|
||||
m_nArgSBufferSize += nCommandSize;
|
||||
|
||||
if ( !m_bIsProcessingCommands || ( nTick > m_nCurrentTick ) )
|
||||
{
|
||||
InsertCommandAtAppropriateTime( hCommand );
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertImmediateCommand( hCommand );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the length of the next command
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::GetNextCommandLength( const char *pText, int nMaxLen, int *pCommandLength, int *pNextCommandOffset )
|
||||
{
|
||||
int nCommandLength = 0;
|
||||
int nNextCommandOffset;
|
||||
bool bIsQuoted = false;
|
||||
bool bIsCommented = false;
|
||||
for ( nNextCommandOffset=0; nNextCommandOffset < nMaxLen; ++nNextCommandOffset, nCommandLength += bIsCommented ? 0 : 1 )
|
||||
{
|
||||
char c = pText[nNextCommandOffset];
|
||||
if ( !bIsCommented )
|
||||
{
|
||||
if ( c == '"' )
|
||||
{
|
||||
bIsQuoted = !bIsQuoted;
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't break if inside a C++ style comment
|
||||
if ( !bIsQuoted && c == '/' )
|
||||
{
|
||||
bIsCommented = ( nNextCommandOffset < nMaxLen-1 ) && pText[nNextCommandOffset+1] == '/';
|
||||
if ( bIsCommented )
|
||||
{
|
||||
++nNextCommandOffset;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// don't break if inside a quoted string
|
||||
if ( !bIsQuoted && c == ';' )
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: This is legacy behavior; should we not break if a \n is inside a quoted string?
|
||||
if ( c == '\n' )
|
||||
break;
|
||||
}
|
||||
|
||||
*pCommandLength = nCommandLength;
|
||||
*pNextCommandOffset = nNextCommandOffset;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Add text to command buffer, return false if it couldn't owing to overflow
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCommandBuffer::AddText( const char *pText, cmd_source_t cmdSource, int nTickDelay )
|
||||
{
|
||||
Assert( nTickDelay >= 0 );
|
||||
|
||||
int nLen = Q_strlen( pText );
|
||||
int nTick = m_nCurrentTick + nTickDelay;
|
||||
|
||||
// Parse the text into distinct commands
|
||||
const char *pCurrentCommand = pText;
|
||||
int nOffsetToNextCommand;
|
||||
for( ; nLen > 0; nLen -= nOffsetToNextCommand+1, pCurrentCommand += nOffsetToNextCommand+1 )
|
||||
{
|
||||
// find a \n or ; line break
|
||||
int nCommandLength;
|
||||
GetNextCommandLength( pCurrentCommand, nLen, &nCommandLength, &nOffsetToNextCommand );
|
||||
if ( nCommandLength <= 0 )
|
||||
continue;
|
||||
|
||||
const char *pArgS;
|
||||
char *pArgV0 = (char*)stackalloc( nCommandLength+1 );
|
||||
CUtlBuffer bufParse( pCurrentCommand, nCommandLength, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
|
||||
ParseArgV0( bufParse, pArgV0, nCommandLength+1, &pArgS );
|
||||
if ( pArgV0[0] == 0 )
|
||||
continue;
|
||||
|
||||
// Deal with the special 'wait' command
|
||||
if ( !Q_stricmp( pArgV0, "wait" ) && IsWaitEnabled() )
|
||||
{
|
||||
int nDelay = pArgS ? atoi( pArgS ) : m_nWaitDelayTicks;
|
||||
nTick += nDelay;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !InsertCommand( pCurrentCommand, nCommandLength, nTick, cmdSource ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Are we in the middle of processing commands?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCommandBuffer::IsProcessingCommands()
|
||||
{
|
||||
return m_bIsProcessingCommands;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Delays all queued commands to execute at a later time
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::DelayAllQueuedCommands( int nDelay )
|
||||
{
|
||||
if ( nDelay <= 0 )
|
||||
return;
|
||||
|
||||
for ( intp i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) )
|
||||
{
|
||||
m_Commands[i].m_nTick += nDelay;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Call this to begin iterating over all commands up to flCurrentTime
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::BeginProcessingCommands( int nDeltaTicks )
|
||||
{
|
||||
if ( nDeltaTicks == 0 )
|
||||
return;
|
||||
|
||||
Assert( !m_bIsProcessingCommands );
|
||||
m_bIsProcessingCommands = true;
|
||||
m_nLastTickToProcess = m_nCurrentTick + nDeltaTicks - 1;
|
||||
|
||||
// Necessary to insert commands while commands are being processed
|
||||
m_hNextCommand = m_Commands.Head();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the next command
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CCommandBuffer::DequeueNextCommand( CCommand* pCommand )
|
||||
{
|
||||
pCommand->Reset();
|
||||
|
||||
Assert( m_bIsProcessingCommands );
|
||||
if ( m_Commands.Count() == 0 )
|
||||
return false;
|
||||
|
||||
intp nHead = m_Commands.Head();
|
||||
Command_t &command = m_Commands[ nHead ];
|
||||
if ( command.m_nTick > m_nLastTickToProcess )
|
||||
return false;
|
||||
|
||||
m_nCurrentTick = command.m_nTick;
|
||||
|
||||
// Copy the current command into a temp buffer
|
||||
// NOTE: This is here to avoid the pointers returned by DequeueNextCommand
|
||||
// to become invalid by calling AddText. Is there a way we can avoid the memcpy?
|
||||
if ( command.m_nBufferSize > 0 )
|
||||
{
|
||||
pCommand->Tokenize( &m_pArgSBuffer[command.m_nFirstArgS], command.m_source );
|
||||
}
|
||||
|
||||
m_Commands.Remove( nHead );
|
||||
|
||||
// Necessary to insert commands while commands are being processed
|
||||
m_hNextCommand = m_Commands.Head();
|
||||
|
||||
// Msg("Dequeue : ");
|
||||
// for ( int i = 0; i < nArgc; ++i )
|
||||
// {
|
||||
// Msg("%s ", m_pCurrentArgv[i] );
|
||||
// }
|
||||
// Msg("\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compacts the command buffer
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::Compact()
|
||||
{
|
||||
// Compress argvbuffer + argv
|
||||
// NOTE: I'm using this choice instead of calling malloc + free
|
||||
// per command to allocate arguments because I expect to post a
|
||||
// bunch of commands but not have many delayed commands;
|
||||
// avoiding the allocation cost seems more important that the memcpy
|
||||
// cost here since I expect to not have much to copy.
|
||||
m_nArgSBufferSize = 0;
|
||||
|
||||
char pTempBuffer[ ARGS_BUFFER_LENGTH ];
|
||||
for ( intp i = m_Commands.Head(); i != m_Commands.InvalidIndex(); i = m_Commands.Next(i) )
|
||||
{
|
||||
Command_t &command = m_Commands[ i ];
|
||||
|
||||
memcpy( &pTempBuffer[m_nArgSBufferSize], &m_pArgSBuffer[command.m_nFirstArgS], command.m_nBufferSize );
|
||||
command.m_nFirstArgS = m_nArgSBufferSize;
|
||||
m_nArgSBufferSize += command.m_nBufferSize;
|
||||
}
|
||||
|
||||
// NOTE: We could also store 2 buffers in the command buffer and switch
|
||||
// between the two to avoid the 2nd memcpy; but again I'm guessing the memory
|
||||
// tradeoff isn't worth it
|
||||
memcpy( m_pArgSBuffer, pTempBuffer, m_nArgSBufferSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Call this to finish iterating over all commands
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCommandBuffer::EndProcessingCommands()
|
||||
{
|
||||
Assert( m_bIsProcessingCommands );
|
||||
m_bIsProcessingCommands = false;
|
||||
m_nCurrentTick = m_nLastTickToProcess + 1;
|
||||
m_hNextCommand = m_Commands.InvalidIndex();
|
||||
|
||||
// Extract commands that are before the end time
|
||||
// NOTE: This is a bug for this to
|
||||
intp i = m_Commands.Head();
|
||||
if ( i == m_Commands.InvalidIndex() )
|
||||
{
|
||||
m_nArgSBufferSize = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
while ( i != m_Commands.InvalidIndex() )
|
||||
{
|
||||
if ( m_Commands[i].m_nTick >= m_nCurrentTick )
|
||||
break;
|
||||
|
||||
AssertMsgOnce( false, "CCommandBuffer::EndProcessingCommands() called before all appropriate commands were dequeued.\n" );
|
||||
int nNext = i;
|
||||
Msg( "Warning: Skipping command %s\n", &m_pArgSBuffer[ m_Commands[i].m_nFirstArgS ] );
|
||||
m_Commands.Remove( i );
|
||||
i = nNext;
|
||||
}
|
||||
|
||||
Compact();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns a handle to the next command to process
|
||||
//-----------------------------------------------------------------------------
|
||||
CommandHandle_t CCommandBuffer::GetNextCommandHandle()
|
||||
{
|
||||
Assert( m_bIsProcessingCommands );
|
||||
return m_Commands.Head();
|
||||
}
|
||||
|
||||
|
||||
|
||||
1538
tier1/convar.cpp
Normal file
1538
tier1/convar.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
tier1/datamanager.cpp
Normal file
435
tier1/datamanager.cpp
Normal file
@@ -0,0 +1,435 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "datamanager.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.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;
|
||||
m_freeOnDestruct = 1;
|
||||
}
|
||||
|
||||
CDataManagerBase::~CDataManagerBase()
|
||||
{
|
||||
Assert( !m_freeOnDestruct || 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 **)stackalloc( 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 **) stackalloc( 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;
|
||||
if ( nBytesToPurge > MemUsed_Inline() )
|
||||
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;
|
||||
}
|
||||
|
||||
void *CDataManagerBase::LockResourceReturnCount( int *pCount, 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);
|
||||
*pCount = ++m_memoryLists[memoryIndex].lockCount;
|
||||
return m_memoryLists[memoryIndex].pStore;
|
||||
}
|
||||
|
||||
*pCount = 0;
|
||||
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 reinterpret_cast< memhandle_t >( (uintp)( 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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
547
tier1/diff.cpp
Normal file
547
tier1/diff.cpp
Normal file
@@ -0,0 +1,547 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
// format of diff output:
|
||||
// 0NN (N=1..127) copy next N literaly
|
||||
//
|
||||
// 1NN (N=1..127) ofs (-128..127) copy next N bytes from original, changin offset by N bytes from
|
||||
// last copy end
|
||||
// 100 N ofs(-32768..32767) copy next N, with larger delta offset
|
||||
// 00 NNNN(1..65535) ofs(-32768..32767) big copy from old
|
||||
// 80 00 NN NN NN big raw copy
|
||||
//
|
||||
// available codes (could be used for additonal compression ops)
|
||||
// long offset form whose offset could have fit in short offset
|
||||
|
||||
// note - this algorithm uses storage equal to 8* the old buffer size. 64k=.5mb
|
||||
|
||||
|
||||
#define MIN_MATCH_LEN 8
|
||||
#define ACCEPTABLE_MATCH_LEN 4096
|
||||
|
||||
struct BlockPtr
|
||||
{
|
||||
BlockPtr *Next;
|
||||
uint8 const *dataptr;
|
||||
};
|
||||
|
||||
template<class T,class V> static inline void AddToHead(T * & head, V * node)
|
||||
{
|
||||
node->Next=head;
|
||||
head=node;
|
||||
}
|
||||
|
||||
void Fail(char const *msg)
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
static void CopyPending(int len, uint8 const *rawbytes,uint8 * &outbuf, uint8 const *limit)
|
||||
{
|
||||
// printf("copy raw len=%d\n",len);
|
||||
if (len<128)
|
||||
{
|
||||
if (limit-outbuf < len+1)
|
||||
Fail("diff buffer overrun");
|
||||
*(outbuf++)=len;
|
||||
memcpy(outbuf,rawbytes,len);
|
||||
outbuf+=len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (limit-outbuf < len+5)
|
||||
Fail("diff buffer overrun");
|
||||
*(outbuf++)=0x80;
|
||||
*(outbuf++)=0x00;
|
||||
*(outbuf++)=(len & 255);
|
||||
*(outbuf++)=((len>>8) & 255);
|
||||
*(outbuf++)=((len>>16) & 255);
|
||||
memcpy(outbuf,rawbytes,len);
|
||||
outbuf+=len;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32 hasher(uint8 const *mdata)
|
||||
{
|
||||
// attempt to scramble the bits of h1 and h2 together
|
||||
uint32 ret=0;
|
||||
for(int i=0;i<MIN_MATCH_LEN;i++)
|
||||
{
|
||||
ret=ret<<4;
|
||||
ret+=(*mdata++);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int FindDiffsForLargeFiles(uint8 const *NewBlock, uint8 const *OldBlock,
|
||||
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,
|
||||
uint32 OutSize,
|
||||
int hashsize)
|
||||
{
|
||||
|
||||
int ret=0;
|
||||
if (OldSize!=NewSize)
|
||||
ret=1;
|
||||
// first, build the hash table
|
||||
BlockPtr **HashedMatches=new BlockPtr* [hashsize];
|
||||
memset(HashedMatches,0,sizeof(HashedMatches[0])*hashsize);
|
||||
BlockPtr *Blocks=0;
|
||||
if (OldSize)
|
||||
Blocks=new BlockPtr[OldSize];
|
||||
BlockPtr *FreeList=Blocks;
|
||||
// now, build the hash table
|
||||
uint8 const *walk=OldBlock;
|
||||
if (OldBlock && OldSize)
|
||||
while(walk<OldBlock+OldSize-MIN_MATCH_LEN)
|
||||
{
|
||||
uint32 hash1=hasher(walk);
|
||||
hash1 &=(hashsize-1);
|
||||
BlockPtr *newnode=FreeList;
|
||||
FreeList++;
|
||||
newnode->dataptr=walk;
|
||||
AddToHead(HashedMatches[hash1],newnode);
|
||||
walk++;
|
||||
}
|
||||
else
|
||||
ret=1;
|
||||
// now, we have the hash table which may be used to search. begin the output step
|
||||
int pending_raw_len=0;
|
||||
walk=NewBlock;
|
||||
uint8 *outbuf=Output;
|
||||
uint8 const *lastmatchend=OldBlock;
|
||||
while(walk<NewBlock+NewSize)
|
||||
{
|
||||
int longest=0;
|
||||
BlockPtr *longest_block=0;
|
||||
if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
|
||||
{
|
||||
// check for a match
|
||||
uint32 hash1=hasher(walk);
|
||||
hash1 &= (hashsize-1);
|
||||
// now, find the longest match in the hash table. If we find one >MIN_MATCH_LEN, take it
|
||||
for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next)
|
||||
{
|
||||
// find the match length
|
||||
int match_of=b->dataptr-lastmatchend;
|
||||
if ((match_of>-32768) && (match_of<32767))
|
||||
{
|
||||
int max_mlength=MIN(65535,OldBlock+OldSize-b->dataptr);
|
||||
max_mlength=MIN(max_mlength,NewBlock+NewSize-walk);
|
||||
int i;
|
||||
for(i=0;i<max_mlength;i++)
|
||||
if (walk[i]!=b->dataptr[i])
|
||||
break;
|
||||
if ((i>MIN_MATCH_LEN) && (i>longest))
|
||||
{
|
||||
longest=i;
|
||||
longest_block=b;
|
||||
if (longest>ACCEPTABLE_MATCH_LEN)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// now, we have a match maybe
|
||||
if (longest_block)
|
||||
{
|
||||
if (pending_raw_len) // must output
|
||||
{
|
||||
ret=1;
|
||||
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
|
||||
pending_raw_len=0;
|
||||
}
|
||||
// now, output copy block
|
||||
int match_of=longest_block->dataptr-lastmatchend;
|
||||
int nremaining=OutSize-(outbuf-Output);
|
||||
|
||||
if (match_of)
|
||||
ret=1;
|
||||
// printf("copy from %x to %x len=%d\n", match_of,outbuf-Output,longest);
|
||||
if (longest>127)
|
||||
{
|
||||
// use really long encoding
|
||||
if (nremaining<5)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=00;
|
||||
*(outbuf++)=(longest & 255);
|
||||
*(outbuf++)=((longest>>8) & 255);
|
||||
*(outbuf++)=(match_of & 255);
|
||||
*(outbuf++)=((match_of>>8) & 255);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((match_of>=-128) && (match_of<128))
|
||||
{
|
||||
if (nremaining<2)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=128+longest;
|
||||
*(outbuf++)=(match_of&255);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use long encoding
|
||||
if (nremaining<4)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=0x80;
|
||||
*(outbuf++)=longest;
|
||||
*(outbuf++)=(match_of & 255);
|
||||
*(outbuf++)=((match_of>>8) & 255);
|
||||
}
|
||||
}
|
||||
lastmatchend=longest_block->dataptr+longest;
|
||||
walk+=longest;
|
||||
}
|
||||
else
|
||||
{
|
||||
walk++;
|
||||
pending_raw_len++;
|
||||
}
|
||||
}
|
||||
// now, flush pending raw copy
|
||||
if (pending_raw_len) // must output
|
||||
{
|
||||
ret=1;
|
||||
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
|
||||
pending_raw_len=0;
|
||||
}
|
||||
delete[] HashedMatches;
|
||||
if (Blocks)
|
||||
delete[] Blocks;
|
||||
DiffListSize=outbuf-Output;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int FindDiffs(uint8 const *NewBlock, uint8 const *OldBlock,
|
||||
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize)
|
||||
{
|
||||
|
||||
int ret=0;
|
||||
if (OldSize!=NewSize)
|
||||
ret=1;
|
||||
// first, build the hash table
|
||||
BlockPtr *HashedMatches[65536];
|
||||
memset(HashedMatches,0,sizeof(HashedMatches));
|
||||
BlockPtr *Blocks=0;
|
||||
if (OldSize)
|
||||
Blocks=new BlockPtr[OldSize];
|
||||
BlockPtr *FreeList=Blocks;
|
||||
// now, build the hash table
|
||||
uint8 const *walk=OldBlock;
|
||||
if (OldBlock && OldSize)
|
||||
while(walk<OldBlock+OldSize-MIN_MATCH_LEN)
|
||||
{
|
||||
uint16 hash1=*((uint16 const *) walk)+*((uint16 const *) walk+2);
|
||||
BlockPtr *newnode=FreeList;
|
||||
FreeList++;
|
||||
newnode->dataptr=walk;
|
||||
AddToHead(HashedMatches[hash1],newnode);
|
||||
walk++;
|
||||
}
|
||||
else
|
||||
ret=1;
|
||||
// now, we have the hash table which may be used to search. begin the output step
|
||||
int pending_raw_len=0;
|
||||
walk=NewBlock;
|
||||
uint8 *outbuf=Output;
|
||||
uint8 const *lastmatchend=OldBlock;
|
||||
while(walk<NewBlock+NewSize)
|
||||
{
|
||||
int longest=0;
|
||||
BlockPtr *longest_block=0;
|
||||
if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
|
||||
{
|
||||
// check for a match
|
||||
uint16 hash1=*((uint16 const *) walk)+*((uint16 const *) walk+2);
|
||||
// now, find the longest match in the hash table. If we find one >MIN_MATCH_LEN, take it
|
||||
for(BlockPtr *b=HashedMatches[hash1];b;b=b->Next)
|
||||
{
|
||||
// find the match length
|
||||
int match_of=b->dataptr-lastmatchend;
|
||||
if ((match_of>-32768) && (match_of<32767))
|
||||
{
|
||||
int max_mlength=MIN(65535,OldBlock+OldSize-b->dataptr);
|
||||
max_mlength=MIN(max_mlength,NewBlock+NewSize-walk);
|
||||
int i;
|
||||
for(i=0;i<max_mlength;i++)
|
||||
if (walk[i]!=b->dataptr[i])
|
||||
break;
|
||||
if ((i>MIN_MATCH_LEN) && (i>longest))
|
||||
{
|
||||
longest=i;
|
||||
longest_block=b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// now, we have a match maybe
|
||||
if (longest_block)
|
||||
{
|
||||
if (pending_raw_len) // must output
|
||||
{
|
||||
ret=1;
|
||||
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
|
||||
pending_raw_len=0;
|
||||
}
|
||||
// now, output copy block
|
||||
int match_of=longest_block->dataptr-lastmatchend;
|
||||
int nremaining=OutSize-(outbuf-Output);
|
||||
if (match_of)
|
||||
ret=1;
|
||||
if (longest>127)
|
||||
{
|
||||
// use really long encoding
|
||||
if (nremaining<5)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=00;
|
||||
*(outbuf++)=(longest & 255);
|
||||
*(outbuf++)=((longest>>8) & 255);
|
||||
*(outbuf++)=(match_of & 255);
|
||||
*(outbuf++)=((match_of>>8) & 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((match_of>=-128) && (match_of<128))
|
||||
{
|
||||
if (nremaining<2)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=128+longest;
|
||||
*(outbuf++)=(match_of&255);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use long encoding
|
||||
if (nremaining<4)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=0x80;
|
||||
*(outbuf++)=longest;
|
||||
*(outbuf++)=(match_of & 255);
|
||||
*(outbuf++)=((match_of>>8) & 255);
|
||||
}
|
||||
}
|
||||
lastmatchend=longest_block->dataptr+longest;
|
||||
walk+=longest;
|
||||
}
|
||||
else
|
||||
{
|
||||
walk++;
|
||||
pending_raw_len++;
|
||||
}
|
||||
}
|
||||
// now, flush pending raw copy
|
||||
if (pending_raw_len) // must output
|
||||
{
|
||||
ret=1;
|
||||
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
|
||||
pending_raw_len=0;
|
||||
}
|
||||
if (Blocks)
|
||||
delete[] Blocks;
|
||||
DiffListSize=outbuf-Output;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int FindDiffsLowMemory(uint8 const *NewBlock, uint8 const *OldBlock,
|
||||
int NewSize, int OldSize, int &DiffListSize,uint8 *Output,uint32 OutSize)
|
||||
{
|
||||
|
||||
int ret=0;
|
||||
if (OldSize!=NewSize)
|
||||
ret=1;
|
||||
uint8 const *old_data_hash[256];
|
||||
memset(old_data_hash,0,sizeof(old_data_hash));
|
||||
int pending_raw_len=0;
|
||||
uint8 const *walk=NewBlock;
|
||||
uint8 const *oldptr=OldBlock;
|
||||
uint8 *outbuf=Output;
|
||||
uint8 const *lastmatchend=OldBlock;
|
||||
while(walk<NewBlock+NewSize)
|
||||
{
|
||||
while( (oldptr-OldBlock<walk-NewBlock+40) && (oldptr-OldBlock<OldSize-MIN_MATCH_LEN))
|
||||
{
|
||||
uint16 hash1=(oldptr[0]+oldptr[1]+oldptr[2]+oldptr[3]) & (NELEMS(old_data_hash)-1);
|
||||
old_data_hash[hash1]=oldptr;
|
||||
oldptr++;
|
||||
}
|
||||
int longest=0;
|
||||
uint8 const *longest_block=0;
|
||||
if (walk<NewBlock+NewSize-MIN_MATCH_LEN)
|
||||
{
|
||||
// check for a match
|
||||
uint16 hash1=(walk[0]+walk[1]+walk[2]+walk[3]) & (NELEMS(old_data_hash)-1);
|
||||
if (old_data_hash[hash1])
|
||||
{
|
||||
int max_bytes_to_compare=MIN(NewBlock+NewSize-walk,OldBlock+OldSize-old_data_hash[hash1]);
|
||||
int nmatches;
|
||||
for(nmatches=0;nmatches<max_bytes_to_compare;nmatches++)
|
||||
if (walk[nmatches]!=old_data_hash[hash1][nmatches])
|
||||
break;
|
||||
if (nmatches>MIN_MATCH_LEN)
|
||||
{
|
||||
longest_block=old_data_hash[hash1];
|
||||
longest=nmatches;
|
||||
}
|
||||
}
|
||||
}
|
||||
// now, we have a match maybe
|
||||
if (longest_block)
|
||||
{
|
||||
if (pending_raw_len) // must output
|
||||
{
|
||||
ret=1;
|
||||
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
|
||||
pending_raw_len=0;
|
||||
}
|
||||
// now, output copy block
|
||||
int match_of=longest_block-lastmatchend;
|
||||
int nremaining=OutSize-(outbuf-Output);
|
||||
if (match_of)
|
||||
ret=1;
|
||||
if (longest>127)
|
||||
{
|
||||
// use really long encoding
|
||||
if (nremaining<5)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=00;
|
||||
*(outbuf++)=(longest & 255);
|
||||
*(outbuf++)=((longest>>8) & 255);
|
||||
*(outbuf++)=(match_of & 255);
|
||||
*(outbuf++)=((match_of>>8) & 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((match_of>=-128) && (match_of<128))
|
||||
{
|
||||
if (nremaining<2)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=128+longest;
|
||||
*(outbuf++)=(match_of&255);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use long encoding
|
||||
if (nremaining<4)
|
||||
Fail("diff buff needs increase");
|
||||
*(outbuf++)=0x80;
|
||||
*(outbuf++)=longest;
|
||||
*(outbuf++)=(match_of & 255);
|
||||
*(outbuf++)=((match_of>>8) & 255);
|
||||
}
|
||||
}
|
||||
lastmatchend=longest_block+longest;
|
||||
walk+=longest;
|
||||
}
|
||||
else
|
||||
{
|
||||
walk++;
|
||||
pending_raw_len++;
|
||||
}
|
||||
}
|
||||
// now, flush pending raw copy
|
||||
if (pending_raw_len) // must output
|
||||
{
|
||||
ret=1;
|
||||
CopyPending(pending_raw_len,walk-pending_raw_len,outbuf,Output+OutSize);
|
||||
pending_raw_len=0;
|
||||
}
|
||||
DiffListSize=outbuf-Output;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
500
tier1/exprevaluator.cpp
Normal file
500
tier1/exprevaluator.cpp
Normal file
@@ -0,0 +1,500 @@
|
||||
//===== Copyright <20> 1996-2006, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
|
||||
// form of a character array). Evaluates C style infix parenthetic logical
|
||||
// expressions. Supports !, ||, &&, (). Symbols are resolved via callback.
|
||||
// Syntax is $<name>. $0 evaluates to false. $<number> evaluates to true.
|
||||
// e.g: ( $1 || ( $FOO || $WHATEVER ) && !$BAR )
|
||||
//===========================================================================//
|
||||
|
||||
#include <ctype.h>
|
||||
#include <vstdlib/ikeyvaluessystem.h>
|
||||
#include "tier1/exprevaluator.h"
|
||||
#include "tier1/convar.h"
|
||||
#include "tier1/fmtstr.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Default conditional symbol handler callback. Symbols are the form $<name>.
|
||||
// Return true or false for the value of the symbol.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool DefaultConditionalSymbolProc( const char *pKey )
|
||||
{
|
||||
if ( pKey[0] == '$' )
|
||||
{
|
||||
pKey++;
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "WIN32" ) )
|
||||
{
|
||||
return IsPC();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "WINDOWS" ) )
|
||||
{
|
||||
return IsPlatformWindowsPC();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "X360" ) )
|
||||
{
|
||||
return IsX360();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "PS3" ) )
|
||||
{
|
||||
return IsPS3();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "OSX" ) )
|
||||
{
|
||||
return IsPlatformOSX();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "LINUX" ) )
|
||||
{
|
||||
return IsPlatformLinux();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "POSIX" ) )
|
||||
{
|
||||
return IsPlatformPosix();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "GAMECONSOLE" ) )
|
||||
{
|
||||
return IsGameConsole();
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "DEMO" ) )
|
||||
{
|
||||
#if defined( _DEMO )
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( !V_stricmp( pKey, "LOWVIOLENCE" ) )
|
||||
{
|
||||
#if defined( _LOWVIOLENCE )
|
||||
return true;
|
||||
#endif
|
||||
// If it is not a LOWVIOLENCE binary build, then fall through
|
||||
// and check if there was a run-time symbol installed for it
|
||||
}
|
||||
|
||||
// don't know it at compile time, so fall through to installed symbol values
|
||||
return KeyValuesSystem()->GetKeyValuesExpressionSymbol( pKey );
|
||||
}
|
||||
|
||||
void DefaultConditionalErrorProc( const char *pReason )
|
||||
{
|
||||
Warning( "Conditional Error: %s\n", pReason );
|
||||
}
|
||||
|
||||
CExpressionEvaluator::CExpressionEvaluator()
|
||||
{
|
||||
m_ExprTree = NULL;
|
||||
}
|
||||
|
||||
CExpressionEvaluator::~CExpressionEvaluator()
|
||||
{
|
||||
FreeTree( m_ExprTree );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets mCurToken to the next token in the input string. Skips all whitespace.
|
||||
//-----------------------------------------------------------------------------
|
||||
char CExpressionEvaluator::GetNextToken( void )
|
||||
{
|
||||
// while whitespace, Increment CurrentPosition
|
||||
while ( m_pExpression[m_CurPosition] == ' ' )
|
||||
++m_CurPosition;
|
||||
|
||||
// CurrentToken = Expression[CurrentPosition]
|
||||
m_CurToken = m_pExpression[m_CurPosition++];
|
||||
|
||||
return m_CurToken;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Utility funcs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CExpressionEvaluator::FreeNode( ExprNode *pNode )
|
||||
{
|
||||
delete pNode;
|
||||
}
|
||||
|
||||
ExprNode *CExpressionEvaluator::AllocateNode( void )
|
||||
{
|
||||
return new ExprNode;
|
||||
}
|
||||
|
||||
void CExpressionEvaluator::FreeTree( ExprTree& node )
|
||||
{
|
||||
if ( !node )
|
||||
return;
|
||||
|
||||
FreeTree( node->left );
|
||||
FreeTree( node->right );
|
||||
FreeNode( node );
|
||||
node = 0;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::IsConditional( bool &bConditional, const char token )
|
||||
{
|
||||
char nextchar = ' ';
|
||||
if ( token == OR_OP || token == AND_OP )
|
||||
{
|
||||
// expect || or &&
|
||||
nextchar = m_pExpression[m_CurPosition++];
|
||||
if ( (token & nextchar) == token )
|
||||
{
|
||||
bConditional = true;
|
||||
}
|
||||
else if ( m_pSyntaxErrorProc )
|
||||
{
|
||||
m_pSyntaxErrorProc( CFmtStr( "Bad expression operator: '%c%c', expected C style operator", token, nextchar ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bConditional = false;
|
||||
}
|
||||
|
||||
// valid
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::IsNotOp( const char token )
|
||||
{
|
||||
if ( token == NOT_OP )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::IsIdentifierOrConstant( const char token )
|
||||
{
|
||||
bool success = false;
|
||||
if ( token == '$' )
|
||||
{
|
||||
// store the entire identifier
|
||||
int i = 0;
|
||||
m_Identifier[i++] = token;
|
||||
while( (V_isalnum( m_pExpression[m_CurPosition] ) || m_pExpression[m_CurPosition] == '_') && i < MAX_IDENTIFIER_LEN )
|
||||
{
|
||||
m_Identifier[i] = m_pExpression[m_CurPosition];
|
||||
++m_CurPosition;
|
||||
++i;
|
||||
}
|
||||
|
||||
if ( i < MAX_IDENTIFIER_LEN - 1 )
|
||||
{
|
||||
m_Identifier[i] = '\0';
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( V_isdigit( token ) )
|
||||
{
|
||||
int i = 0;
|
||||
m_Identifier[i++] = token;
|
||||
while( V_isdigit( m_pExpression[m_CurPosition] ) && ( i < MAX_IDENTIFIER_LEN ) )
|
||||
{
|
||||
m_Identifier[i] = m_pExpression[m_CurPosition];
|
||||
++m_CurPosition;
|
||||
++i;
|
||||
}
|
||||
if ( i < MAX_IDENTIFIER_LEN - 1 )
|
||||
{
|
||||
m_Identifier[i] = '\0';
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CExpressionEvaluator::MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right )
|
||||
{
|
||||
tree = AllocateNode();
|
||||
tree->left = left;
|
||||
tree->right = right;
|
||||
tree->kind = kind;
|
||||
|
||||
switch ( kind )
|
||||
{
|
||||
case CONDITIONAL:
|
||||
tree->data.cond = token;
|
||||
break;
|
||||
|
||||
case LITERAL:
|
||||
if ( V_isdigit( m_Identifier[0] ) )
|
||||
{
|
||||
tree->data.value = ( atoi( m_Identifier ) != 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
tree->data.value = m_pGetSymbolProc( m_Identifier );
|
||||
}
|
||||
break;
|
||||
|
||||
case NOT:
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( m_pSyntaxErrorProc )
|
||||
{
|
||||
Assert( 0 );
|
||||
m_pSyntaxErrorProc( CFmtStr( "Logic Error in CExpressionEvaluator" ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes a factor :: { <expression> } | <identifier>.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::MakeFactor( ExprTree &tree )
|
||||
{
|
||||
if ( m_CurToken == '(' )
|
||||
{
|
||||
// Get the next token
|
||||
GetNextToken();
|
||||
|
||||
// Make an expression, setting Tree to point to it
|
||||
if ( !MakeExpression( tree ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( IsIdentifierOrConstant( m_CurToken ) )
|
||||
{
|
||||
// Make a literal node, set Tree to point to it, set left/right children to NULL.
|
||||
if ( !MakeExprNode( tree, m_CurToken, LITERAL, NULL, NULL ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( IsNotOp( m_CurToken ) )
|
||||
{
|
||||
// do nothing
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This must be a bad token
|
||||
if ( m_pSyntaxErrorProc )
|
||||
{
|
||||
m_pSyntaxErrorProc( CFmtStr( "Bad expression token: %c", m_CurToken ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the next token
|
||||
GetNextToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes a term :: <factor> { <not> }.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::MakeTerm( ExprTree &tree )
|
||||
{
|
||||
// Make a factor, setting Tree to point to it
|
||||
if ( !MakeFactor( tree ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// while the next token is !
|
||||
while ( IsNotOp( m_CurToken ) )
|
||||
{
|
||||
// Make an operator node, setting left child to Tree and right to NULL. (Tree points to new node)
|
||||
if ( !MakeExprNode( tree, m_CurToken, NOT, tree, NULL ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the next token.
|
||||
GetNextToken();
|
||||
|
||||
// Make a factor, setting the right child of Tree to point to it.
|
||||
if ( !MakeFactor( tree->right ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes a complete expression :: <term> { <cond> <term> }.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::MakeExpression( ExprTree &tree )
|
||||
{
|
||||
// Make a term, setting Tree to point to it
|
||||
if ( !MakeTerm( tree ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// while the next token is a conditional
|
||||
while ( 1 )
|
||||
{
|
||||
bool bConditional = false;
|
||||
bool bValid = IsConditional( bConditional, m_CurToken );
|
||||
if ( !bValid )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !bConditional )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Make a conditional node, setting left child to Tree and right to NULL. (Tree points to new node)
|
||||
if ( !MakeExprNode( tree, m_CurToken, CONDITIONAL, tree, NULL ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the next token.
|
||||
GetNextToken();
|
||||
|
||||
// Make a term, setting the right child of Tree to point to it.
|
||||
if ( !MakeTerm( tree->right ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns true for success, false for failure
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::BuildExpression( void )
|
||||
{
|
||||
// Get the first token, and build the tree.
|
||||
GetNextToken();
|
||||
|
||||
return ( MakeExpression( m_ExprTree ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns the value of the node after resolving all children
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::SimplifyNode( ExprTree& node )
|
||||
{
|
||||
if ( !node )
|
||||
return false;
|
||||
|
||||
// Simplify the left and right children of this node
|
||||
bool leftVal = SimplifyNode(node->left);
|
||||
bool rightVal = SimplifyNode(node->right);
|
||||
|
||||
// Simplify this node
|
||||
switch( node->kind )
|
||||
{
|
||||
case NOT:
|
||||
// the child of '!' is always to the right
|
||||
node->data.value = !rightVal;
|
||||
break;
|
||||
|
||||
case CONDITIONAL:
|
||||
if ( node->data.cond == AND_OP )
|
||||
{
|
||||
node->data.value = leftVal && rightVal;
|
||||
}
|
||||
else // OR_OP
|
||||
{
|
||||
node->data.value = leftVal || rightVal;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // LITERAL
|
||||
break;
|
||||
}
|
||||
|
||||
// This node has beed resolved
|
||||
node->kind = LITERAL;
|
||||
return node->data.value;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Interface to solve a conditional expression. Returns false on failure, Result is undefined.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CExpressionEvaluator::Evaluate( bool &bResult, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc, SyntaxErrorProc_t pSyntaxErrorProc )
|
||||
{
|
||||
if ( !pInfixExpression )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// for caller simplicity, we strip of any enclosing braces
|
||||
// strip the bracketing [] if present
|
||||
char szCleanToken[512];
|
||||
if ( pInfixExpression[0] == '[' )
|
||||
{
|
||||
int len = V_strlen( pInfixExpression );
|
||||
|
||||
// SECURITY: Bail on input buffers that are too large, they're used for RCEs and we don't
|
||||
// need to support them.
|
||||
if ( len + 1 > ARRAYSIZE( szCleanToken ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
V_strncpy( szCleanToken, pInfixExpression + 1, len );
|
||||
len--;
|
||||
if ( szCleanToken[len-1] == ']' )
|
||||
{
|
||||
szCleanToken[len-1] = '\0';
|
||||
}
|
||||
pInfixExpression = szCleanToken;
|
||||
}
|
||||
|
||||
// reset state
|
||||
m_pExpression = pInfixExpression;
|
||||
m_pGetSymbolProc = pGetSymbolProc ? pGetSymbolProc : DefaultConditionalSymbolProc;
|
||||
m_pSyntaxErrorProc = pSyntaxErrorProc ? pSyntaxErrorProc : DefaultConditionalErrorProc;
|
||||
m_ExprTree = 0;
|
||||
m_CurPosition = 0;
|
||||
m_CurToken = 0;
|
||||
|
||||
// Building the expression tree will fail on bad syntax
|
||||
bool bValid = BuildExpression();
|
||||
if ( bValid )
|
||||
{
|
||||
bResult = SimplifyNode( m_ExprTree );
|
||||
}
|
||||
|
||||
// don't leak
|
||||
FreeTree( m_ExprTree );
|
||||
m_ExprTree = NULL;
|
||||
|
||||
return bValid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1927
tier1/fileio.cpp
Normal file
1927
tier1/fileio.cpp
Normal file
File diff suppressed because it is too large
Load Diff
51
tier1/generate_constructors.pl
Normal file
51
tier1/generate_constructors.pl
Normal file
@@ -0,0 +1,51 @@
|
||||
#!perl
|
||||
|
||||
print `p4 edit ../public/tier1/utlstringtoken_generated_contructors.h`;
|
||||
|
||||
open( FOUT, ">../public/tier1/utlstringtoken_generated_contructors.h" ) || die "cant open output file";
|
||||
|
||||
print FOUT "//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======//\n";
|
||||
print FOUT "//\n";
|
||||
print FOUT "// Purpose: inlines for compile-time hashing of constant strings\n";
|
||||
print FOUT "//\n";
|
||||
print FOUT "// $NoKeywords: \$\n";
|
||||
print FOUT "//\n";
|
||||
print FOUT "//===========================================================================//\n";
|
||||
print FOUT "// DO NOT EDIT THIS FILE - IT IS GENERATED BY RUNNING GENERATE_CONSTRUCTORS.PL\n\n";
|
||||
|
||||
print FOUT "#define TOLOWERU( c ) ( ( uint32 ) ( ( ( c >= 'A' ) && ( c <= 'Z' ) )? c + 32 : c ) )\n";
|
||||
|
||||
|
||||
# generate for lengths 1 to 30
|
||||
for( $i = 1; $i < 30; $i++ )
|
||||
{
|
||||
$len = $i - 1;
|
||||
print FOUT "FORCEINLINE CUtlStringToken( const char ( \&str )[$i] )\n{\n";
|
||||
print FOUT "\tconst uint32 m = 0x5bd1e995;\n";
|
||||
print FOUT "\tuint32 h = STRINGTOKEN_MURMURHASH_SEED ^ $len;\n";
|
||||
$curpos = 0;
|
||||
print FOUT "\tuint32 k;\n" if ( $len >= 4 );
|
||||
print FOUT "\tconst int r = 24;\n" if ( $len >= 4 );
|
||||
while( $len >= 4)
|
||||
{
|
||||
print FOUT "\tk = TOLOWERU( str[ $curpos ] ) + ( TOLOWERU( str[ $curpos + 1 ] ) << 8 ) + ( TOLOWERU( str[ $curpos + 2 ] ) << 16 ) +";
|
||||
print FOUT "( TOLOWERU( str[ $curpos + 3 ] ) << 24 );\n";
|
||||
print FOUT "\tk *= m;\n";
|
||||
print FOUT "\tk ^= k >> r;\n";
|
||||
print FOUT "\tk *= m;\n";
|
||||
print FOUT "\th *= m;\n";
|
||||
print FOUT "\th ^= k;\n";
|
||||
$curpos += 4;
|
||||
$len -= 4;
|
||||
}
|
||||
|
||||
print FOUT "\th ^= TOLOWERU( str[ $curpos + 2 ] ) << 16;\n" if ( $len >= 3 );
|
||||
print FOUT "\th ^= TOLOWERU( str[ $curpos + 1 ] ) << 8;\n" if ( $len >= 2 );
|
||||
print FOUT "\th ^= TOLOWERU( str[ $curpos + 0 ] );\n" if ( $len >= 1 );
|
||||
print FOUT "\th *= m;\n" if ( $len >= 1 );
|
||||
print FOUT "\th ^= h >> 13;\n";
|
||||
print FOUT "\th *= m;\n";
|
||||
print FOUT "\th ^= h >> 15;\n";
|
||||
print FOUT "\tm_nHashCode = h;\n}\n\n";
|
||||
}
|
||||
|
||||
431
tier1/generichash.cpp
Normal file
431
tier1/generichash.cpp
Normal file
@@ -0,0 +1,431 @@
|
||||
//======= Copyright © 2005, , 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"
|
||||
#include "tier1/strtools.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
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 FASTCALL HashStringCaselessConventional( const char *pszKey )
|
||||
{
|
||||
uint32 hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add
|
||||
hash += ( 2 * V_strlen( pszKey ) ); // Add the string length * 2 to the hash to give it more variety
|
||||
|
||||
for( ; *pszKey ; pszKey++ )
|
||||
{
|
||||
hash = ( ( hash << 5 ) + hash ) + (uint8)tolower(*pszKey);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// int hash
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned FASTCALL HashInt( const int n )
|
||||
{
|
||||
register unsigned even, odd;
|
||||
odd = g_nRandomValues[(((unsigned)n >> 8) & 0xff)];
|
||||
even = g_nRandomValues[odd ^ ((unsigned)n >> 24)];
|
||||
odd = g_nRandomValues[even ^ ((unsigned)n >> 16) & 0xff];
|
||||
even = g_nRandomValues[odd ^ ((unsigned)n >> 8) & 0xff];
|
||||
odd = g_nRandomValues[even ^ ((unsigned)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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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 = V_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;
|
||||
}
|
||||
|
||||
701
tier1/interface.cpp
Normal file
701
tier1/interface.cpp
Normal file
@@ -0,0 +1,701 @@
|
||||
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if !defined( DONT_PROTECT_FILEIO_FUNCTIONS )
|
||||
#define DONT_PROTECT_FILEIO_FUNCTIONS // for protected_things.h
|
||||
#endif
|
||||
|
||||
#if defined( PROTECTED_THINGS_ENABLE )
|
||||
#undef PROTECTED_THINGS_ENABLE // from protected_things.h
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "tier1/interface.h"
|
||||
#include "basetypes.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier0/stacktools.h"
|
||||
#include "tier0/threadtools.h"
|
||||
#ifdef _WIN32
|
||||
#include <direct.h> // getcwd
|
||||
#endif
|
||||
#if defined( _X360 )
|
||||
#include "xbox/xbox_win32stubs.h"
|
||||
#endif
|
||||
|
||||
#ifdef _PS3
|
||||
#include "sys/prx.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "ps3/ps3_platform.h"
|
||||
#include "ps3/ps3_win32stubs.h"
|
||||
#include "ps3/ps3_helpers.h"
|
||||
#include "ps3_pathinfo.h"
|
||||
#elif defined(POSIX)
|
||||
#include "tier0/platform.h"
|
||||
#endif // _PS3
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// InterfaceReg.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
#ifdef POSIX
|
||||
DLL_GLOBAL_EXPORT
|
||||
#endif
|
||||
InterfaceReg *s_pInterfaceRegs;
|
||||
|
||||
InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) :
|
||||
m_pName(pName)
|
||||
{
|
||||
m_CreateFn = fn;
|
||||
m_pNext = s_pInterfaceRegs;
|
||||
s_pInterfaceRegs = this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// CreateInterface.
|
||||
// This is the primary exported function by a dll, referenced by name via dynamic binding
|
||||
// that exposes an opqaue function pointer to the interface.
|
||||
//
|
||||
// We have the Internal variant so Sys_GetFactoryThis() returns the correct internal
|
||||
// symbol under GCC/Linux/Mac as CreateInterface is DLL_EXPORT so its global so the loaders
|
||||
// on those OS's pick exactly 1 of the CreateInterface symbols to be the one that is process wide and
|
||||
// all Sys_GetFactoryThis() calls find that one, which doesn't work. Using the internal walkthrough here
|
||||
// makes sure Sys_GetFactoryThis() has the dll specific symbol and GetProcAddress() returns the module specific
|
||||
// function for CreateInterface again getting the dll specific symbol we need.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
void* CreateInterfaceInternal( const char *pName, int *pReturnCode )
|
||||
{
|
||||
InterfaceReg *pCur;
|
||||
|
||||
for (pCur=s_pInterfaceRegs; pCur; pCur=pCur->m_pNext)
|
||||
{
|
||||
if (strcmp(pCur->m_pName, pName) == 0)
|
||||
{
|
||||
if (pReturnCode)
|
||||
{
|
||||
*pReturnCode = IFACE_OK;
|
||||
}
|
||||
return pCur->m_CreateFn();
|
||||
}
|
||||
}
|
||||
|
||||
if (pReturnCode)
|
||||
{
|
||||
*pReturnCode = IFACE_FAILED;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* CreateInterface( const char *pName, int *pReturnCode )
|
||||
{
|
||||
return CreateInterfaceInternal( pName, pReturnCode );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined( POSIX ) && !defined( _PS3 )
|
||||
// Linux doesn't have this function so this emulates its functionality
|
||||
void *GetModuleHandle(const char *name)
|
||||
{
|
||||
void *handle;
|
||||
|
||||
if( name == NULL )
|
||||
{
|
||||
// hmm, how can this be handled under linux....
|
||||
// is it even needed?
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( (handle=dlopen(name, RTLD_NOW))==NULL)
|
||||
{
|
||||
printf("DLOPEN Error:%s\n",dlerror());
|
||||
// couldn't open this file
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read "man dlopen" for details
|
||||
// in short dlopen() inc a ref count
|
||||
// so dec the ref count by performing the close
|
||||
dlclose(handle);
|
||||
return handle;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns a pointer to a function, given a module
|
||||
// Input : pModuleName - module name
|
||||
// *pName - proc name
|
||||
//-----------------------------------------------------------------------------
|
||||
static void *Sys_GetProcAddress( const char *pModuleName, const char *pName )
|
||||
{
|
||||
#if defined( _PS3 )
|
||||
Assert( !"Unsupported, use HMODULE" );
|
||||
return NULL;
|
||||
#else // !_PS3
|
||||
HMODULE hModule = (HMODULE)GetModuleHandle( pModuleName );
|
||||
#if defined( WIN32 )
|
||||
return (void *)GetProcAddress( hModule, pName );
|
||||
#else // !WIN32
|
||||
return (void *)dlsym( (void *)hModule, pName );
|
||||
#endif // WIN32
|
||||
#endif // _PS3
|
||||
}
|
||||
|
||||
static void *Sys_GetProcAddress( HMODULE hModule, const char *pName )
|
||||
{
|
||||
#if defined( WIN32 )
|
||||
return (void *)GetProcAddress( hModule, pName );
|
||||
#elif defined( _PS3 )
|
||||
PS3_LoadAppSystemInterface_Parameters_t *pPRX = reinterpret_cast< PS3_LoadAppSystemInterface_Parameters_t * >( hModule );
|
||||
if ( !pPRX )
|
||||
return NULL;
|
||||
if ( !strcmp( pName, CREATEINTERFACE_PROCNAME ) )
|
||||
return reinterpret_cast< void * >( pPRX->pfnCreateInterface );
|
||||
Assert( !"Unknown PRX function requested!" );
|
||||
return NULL;
|
||||
#else
|
||||
return (void *)dlsym( (void *)hModule, pName );
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Sys_IsDebuggerPresent()
|
||||
{
|
||||
return Plat_IsInDebugSession();
|
||||
}
|
||||
|
||||
struct ThreadedLoadLibaryContext_t
|
||||
{
|
||||
const char *m_pLibraryName;
|
||||
HMODULE m_hLibrary;
|
||||
DWORD m_nError;
|
||||
ThreadedLoadLibaryContext_t() : m_pLibraryName(NULL), m_hLibrary(0), m_nError(0) {}
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// wraps LoadLibraryEx() since 360 doesn't support that
|
||||
static HMODULE InternalLoadLibrary( const char *pName )
|
||||
{
|
||||
#if defined(_X360)
|
||||
HMODULE result = LoadLibrary( pName );
|
||||
if (result == NULL)
|
||||
{
|
||||
Warning( "Failed to load library %s: %d\n", pName, GetLastError() );
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
return LoadLibraryEx( pName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
|
||||
#endif
|
||||
}
|
||||
uintp ThreadedLoadLibraryFunc( void *pParam )
|
||||
{
|
||||
ThreadedLoadLibaryContext_t *pContext = (ThreadedLoadLibaryContext_t*)pParam;
|
||||
pContext->m_hLibrary = InternalLoadLibrary(pContext->m_pLibraryName);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// global to propagate a library load error from thread into Sys_LoadModule
|
||||
static DWORD g_nLoadLibraryError = 0;
|
||||
|
||||
static HMODULE Sys_LoadLibraryGuts( const char *pLibraryName )
|
||||
{
|
||||
#ifdef PLATFORM_PS3
|
||||
|
||||
PS3_LoadAppSystemInterface_Parameters_t *pPRX = new PS3_LoadAppSystemInterface_Parameters_t;
|
||||
Q_memset( pPRX, 0, sizeof( PS3_LoadAppSystemInterface_Parameters_t ) );
|
||||
pPRX->cbSize = sizeof( PS3_LoadAppSystemInterface_Parameters_t );
|
||||
int iResult = PS3_PrxLoad( pLibraryName, pPRX );
|
||||
if ( iResult < CELL_OK )
|
||||
{
|
||||
delete pPRX;
|
||||
return NULL;
|
||||
}
|
||||
return reinterpret_cast< HMODULE >( pPRX );
|
||||
|
||||
#else
|
||||
|
||||
char str[1024];
|
||||
|
||||
// How to get a string out of a #define on the command line.
|
||||
const char *pModuleExtension = DLL_EXT_STRING;
|
||||
const char *pModuleAddition = pModuleExtension;
|
||||
|
||||
Q_strncpy( str, pLibraryName, sizeof(str) );
|
||||
if ( !Q_stristr( str, pModuleExtension ) )
|
||||
{
|
||||
if ( IsX360() )
|
||||
{
|
||||
Q_StripExtension( str, str, sizeof(str) );
|
||||
}
|
||||
Q_strncat( str, pModuleAddition, sizeof(str) );
|
||||
}
|
||||
Q_FixSlashes( str );
|
||||
|
||||
#ifdef _WIN32
|
||||
ThreadedLoadLibraryFunc_t threadFunc = GetThreadedLoadLibraryFunc();
|
||||
if ( !threadFunc )
|
||||
{
|
||||
HMODULE retVal = InternalLoadLibrary( str );
|
||||
if( retVal )
|
||||
{
|
||||
StackToolsNotify_LoadedLibrary( str );
|
||||
}
|
||||
#if 0 // you can enable this block to help track down why a module isn't loading:
|
||||
else
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
char buf[1024];
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
0, // Default language
|
||||
(LPTSTR) buf,
|
||||
1023,
|
||||
NULL // no insert arguments
|
||||
);
|
||||
Warning( "Could not load %s: %s\n", str, buf );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
ThreadedLoadLibaryContext_t context;
|
||||
context.m_pLibraryName = str;
|
||||
context.m_hLibrary = 0;
|
||||
|
||||
ThreadHandle_t h = CreateSimpleThread( ThreadedLoadLibraryFunc, &context );
|
||||
|
||||
#ifdef _X360
|
||||
ThreadSetAffinity( h, XBOX_PROCESSOR_3 );
|
||||
#endif
|
||||
|
||||
unsigned int nTimeout = 0;
|
||||
while( WaitForSingleObject( (HANDLE)h, nTimeout ) == WAIT_TIMEOUT )
|
||||
{
|
||||
nTimeout = threadFunc();
|
||||
}
|
||||
|
||||
ReleaseThreadHandle( h );
|
||||
|
||||
if( context.m_hLibrary )
|
||||
{
|
||||
g_nLoadLibraryError = 0;
|
||||
StackToolsNotify_LoadedLibrary( str );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_nLoadLibraryError = context.m_nError;
|
||||
}
|
||||
|
||||
return context.m_hLibrary;
|
||||
|
||||
#elif defined( POSIX ) && !defined( _PS3 )
|
||||
HMODULE ret = (HMODULE)dlopen( str, RTLD_NOW );
|
||||
if ( ! ret )
|
||||
{
|
||||
const char *pError = dlerror();
|
||||
if ( pError && ( strstr( pError, "No such file" ) == 0 ) && ( strstr( pError, "image not found") == 0 ) )
|
||||
{
|
||||
Msg( " failed to dlopen %s error=%s\n", str, pError );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// if( ret )
|
||||
// StackToolsNotify_LoadedLibrary( str );
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static HMODULE Sys_LoadLibrary( const char *pLibraryName )
|
||||
{
|
||||
// load a library. If a library suffix is set, look for the library first with that name
|
||||
char *pSuffix = NULL;
|
||||
|
||||
if ( CommandLine()->FindParm( "-xlsp" ) )
|
||||
{
|
||||
pSuffix = "_xlsp";
|
||||
}
|
||||
#ifdef POSIX
|
||||
else if ( CommandLine()->FindParm( "-valveinternal" ) )
|
||||
{
|
||||
pSuffix = "_valveinternal";
|
||||
}
|
||||
#endif
|
||||
#ifdef IS_WINDOWS_PC
|
||||
else if ( CommandLine()->FindParm( "-ds" ) ) // windows DS bins
|
||||
{
|
||||
pSuffix = "_ds";
|
||||
}
|
||||
#endif
|
||||
if ( pSuffix )
|
||||
{
|
||||
char nameBuf[MAX_PATH];
|
||||
strcpy( nameBuf, pLibraryName );
|
||||
char *pDot = strchr( nameBuf, '.' );
|
||||
if ( pDot )
|
||||
*pDot = 0;
|
||||
V_strncat( nameBuf, pSuffix, sizeof( nameBuf ), COPY_ALL_CHARACTERS );
|
||||
HMODULE hRet = Sys_LoadLibraryGuts( nameBuf );
|
||||
if ( hRet )
|
||||
return hRet;
|
||||
}
|
||||
return Sys_LoadLibraryGuts( pLibraryName );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Keeps a flag if the current dll/exe loaded any debug modules
|
||||
// This flag can also get set if the current process discovers any other debug
|
||||
// modules loaded by other dlls
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool s_bRunningWithDebugModules = false;
|
||||
|
||||
#ifdef IS_WINDOWS_PC
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Construct a process-specific name for kernel object to track
|
||||
// if any debug modules were loaded
|
||||
//-----------------------------------------------------------------------------
|
||||
static void DebugKernelMemoryObjectName( char *pszNameBuffer )
|
||||
{
|
||||
sprintf( pszNameBuffer, "VALVE-MODULE-DEBUG-%08X", GetCurrentProcessId() );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Loads a DLL/component from disk and returns a handle to it
|
||||
// Input : *pModuleName - filename of the component
|
||||
// Output : opaque handle to the module (hides system dependency)
|
||||
//-----------------------------------------------------------------------------
|
||||
CSysModule *Sys_LoadModule( const char *pModuleName )
|
||||
{
|
||||
// If using the Steam filesystem, either the DLL must be a minimum footprint
|
||||
// file in the depot (MFP) or a filesystem GetLocalCopy() call must be made
|
||||
// prior to the call to this routine.
|
||||
HMODULE hDLL = NULL;
|
||||
|
||||
char alteredFilename[ MAX_PATH ];
|
||||
if ( IsPS3() )
|
||||
{
|
||||
// PS3's load module *must* be fed extensions. If the extension is missing, add it.
|
||||
if (!( strstr(pModuleName, ".sprx") || strstr(pModuleName, ".prx") ))
|
||||
{
|
||||
strncpy( alteredFilename, pModuleName, MAX_PATH );
|
||||
strncat( alteredFilename, DLL_EXT_STRING, MAX_PATH );
|
||||
pModuleName = alteredFilename;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
alteredFilename; // just to quash the warning
|
||||
}
|
||||
|
||||
if ( !Q_IsAbsolutePath( pModuleName ) )
|
||||
{
|
||||
// full path wasn't passed in, using the current working dir
|
||||
char szAbsoluteModuleName[1024];
|
||||
#if defined( _PS3 )
|
||||
// getcwd not supported on ps3; use PRX path instead (TODO: fallback to DISK path too)
|
||||
Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s",
|
||||
g_pPS3PathInfo->PrxPath(), pModuleName );
|
||||
hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
|
||||
#else // !_PS3
|
||||
char szCwd[1024];
|
||||
_getcwd( szCwd, sizeof( szCwd ) );
|
||||
if ( IsX360() )
|
||||
{
|
||||
int i = CommandLine()->FindParm( "-basedir" );
|
||||
if ( i )
|
||||
{
|
||||
strcpy( szCwd, CommandLine()->GetParm( i+1 ) );
|
||||
}
|
||||
}
|
||||
if (szCwd[strlen(szCwd) - 1] == '/' || szCwd[strlen(szCwd) - 1] == '\\' )
|
||||
{
|
||||
szCwd[strlen(szCwd) - 1] = 0;
|
||||
}
|
||||
|
||||
size_t cCwd = strlen( szCwd );
|
||||
if ( strstr( pModuleName, "bin/") == pModuleName || ( szCwd[ cCwd - 1 ] == 'n' && szCwd[ cCwd - 2 ] == 'i' && szCwd[ cCwd - 3 ] == 'b' ) )
|
||||
{
|
||||
// don't make bin/bin path
|
||||
Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s", szCwd, pModuleName );
|
||||
}
|
||||
hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
|
||||
#endif // _PS3
|
||||
}
|
||||
|
||||
if ( !hDLL )
|
||||
{
|
||||
// full path failed, let LoadLibrary() try to search the PATH now
|
||||
hDLL = Sys_LoadLibrary( pModuleName );
|
||||
#if defined( _DEBUG )
|
||||
if ( !hDLL )
|
||||
{
|
||||
// So you can see what the error is in the debugger...
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
char *lpMsgBuf;
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
LocalFree( (HLOCAL)lpMsgBuf );
|
||||
#elif defined( _X360 )
|
||||
DWORD error = g_nLoadLibraryError ? g_nLoadLibraryError : GetLastError();
|
||||
Msg( "Error(%d) - Failed to load %s:\n", error, pModuleName );
|
||||
#elif defined( _PS3 )
|
||||
Msg( "Failed to load %s:\n", pModuleName );
|
||||
#else
|
||||
Msg( "Failed to load %s: %s\n", pModuleName, dlerror() );
|
||||
#endif // _WIN32
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
// If running in the debugger, assume debug binaries are okay, otherwise they must run with -allowdebug
|
||||
if ( !IsGameConsole() && Sys_GetProcAddress( hDLL, "BuiltDebug" ) )
|
||||
{
|
||||
if ( hDLL && !CommandLine()->FindParm( "-allowdebug" ) &&
|
||||
!Sys_IsDebuggerPresent() )
|
||||
{
|
||||
Error( "Module %s is a debug build\n", pModuleName );
|
||||
}
|
||||
|
||||
DevWarning( "Module %s is a debug build\n", pModuleName );
|
||||
|
||||
if ( !s_bRunningWithDebugModules )
|
||||
{
|
||||
s_bRunningWithDebugModules = true;
|
||||
|
||||
#ifdef IS_WINDOWS_PC
|
||||
char chMemoryName[ MAX_PATH ];
|
||||
DebugKernelMemoryObjectName( chMemoryName );
|
||||
|
||||
(void) CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, chMemoryName );
|
||||
// Created a shared memory kernel object specific to process id
|
||||
// Existence of this object indicates that we have debug modules loaded
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return reinterpret_cast<CSysModule *>(hDLL);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Determine if any debug modules were loaded
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Sys_RunningWithDebugModules()
|
||||
{
|
||||
if ( !s_bRunningWithDebugModules )
|
||||
{
|
||||
#ifdef IS_WINDOWS_PC
|
||||
char chMemoryName[ MAX_PATH ];
|
||||
DebugKernelMemoryObjectName( chMemoryName );
|
||||
|
||||
HANDLE hObject = OpenFileMapping( FILE_MAP_READ, FALSE, chMemoryName );
|
||||
if ( hObject && hObject != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle( hObject );
|
||||
s_bRunningWithDebugModules = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return s_bRunningWithDebugModules;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Unloads a DLL/component from
|
||||
// Input : *pModuleName - filename of the component
|
||||
// Output : opaque handle to the module (hides system dependency)
|
||||
//-----------------------------------------------------------------------------
|
||||
void Sys_UnloadModule( CSysModule *pModule )
|
||||
{
|
||||
if ( !pModule )
|
||||
return;
|
||||
|
||||
HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
|
||||
|
||||
#ifdef _WIN32
|
||||
FreeLibrary( hDLL );
|
||||
#elif defined( _PS3 )
|
||||
PS3_PrxUnload( ( ( PS3_PrxLoadParametersBase_t *)pModule )->sysPrxId );
|
||||
delete ( PS3_PrxLoadParametersBase_t *)pModule;
|
||||
#elif defined( POSIX )
|
||||
//$$$$$$ mikesart: for testing with valgrind don't unload so... dlclose((void *)hDLL);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns a pointer to a function, given a module
|
||||
// Input : module - windows HMODULE from Sys_LoadModule()
|
||||
// *pName - proc name
|
||||
// Output : factory for this module
|
||||
//-----------------------------------------------------------------------------
|
||||
CreateInterfaceFn Sys_GetFactory( CSysModule *pModule )
|
||||
{
|
||||
if ( !pModule )
|
||||
return NULL;
|
||||
|
||||
HMODULE hDLL = reinterpret_cast<HMODULE>(pModule);
|
||||
#ifdef _WIN32
|
||||
return reinterpret_cast<CreateInterfaceFn>(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
|
||||
#elif defined( _PS3 )
|
||||
return reinterpret_cast<CreateInterfaceFn>(Sys_GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME ));
|
||||
#elif defined( POSIX )
|
||||
// Linux gives this error:
|
||||
//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory
|
||||
//(CSysModule *)) (const char *, int *)':
|
||||
//../public/interface.cpp:154: ISO C++ forbids casting between
|
||||
//pointer-to-function and pointer-to-object
|
||||
//
|
||||
// so lets get around it :)
|
||||
return (CreateInterfaceFn)(GetProcAddress( (void *)hDLL, CREATEINTERFACE_PROCNAME ));
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the instance of this module
|
||||
// Output : interface_instance_t
|
||||
//-----------------------------------------------------------------------------
|
||||
CreateInterfaceFn Sys_GetFactoryThis( void )
|
||||
{
|
||||
return &CreateInterfaceInternal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the instance of the named module
|
||||
// Input : *pModuleName - name of the module
|
||||
// Output : interface_instance_t - instance of that module
|
||||
//-----------------------------------------------------------------------------
|
||||
CreateInterfaceFn Sys_GetFactory( const char *pModuleName )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return static_cast<CreateInterfaceFn>( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
|
||||
#elif defined( _PS3 )
|
||||
Assert( 0 );
|
||||
return NULL;
|
||||
#elif defined(POSIX)
|
||||
// see Sys_GetFactory( CSysModule *pModule ) for an explanation
|
||||
return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: get the interface for the specified module and version
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Sys_LoadInterface(
|
||||
const char *pModuleName,
|
||||
const char *pInterfaceVersionName,
|
||||
CSysModule **pOutModule,
|
||||
void **pOutInterface )
|
||||
{
|
||||
CSysModule *pMod = Sys_LoadModule( pModuleName );
|
||||
if ( !pMod )
|
||||
return false;
|
||||
|
||||
CreateInterfaceFn fn = Sys_GetFactory( pMod );
|
||||
if ( !fn )
|
||||
{
|
||||
Sys_UnloadModule( pMod );
|
||||
return false;
|
||||
}
|
||||
|
||||
*pOutInterface = fn( pInterfaceVersionName, NULL );
|
||||
if ( !( *pOutInterface ) )
|
||||
{
|
||||
Sys_UnloadModule( pMod );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( pOutModule )
|
||||
*pOutModule = pMod;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name.
|
||||
//
|
||||
// When the singleton goes out of scope (.dll unload if at module scope),
|
||||
// then it'll call Sys_UnloadModule on the module so that the refcount is decremented
|
||||
// and the .dll actually can unload from memory.
|
||||
//-----------------------------------------------------------------------------
|
||||
CDllDemandLoader::CDllDemandLoader( char const *pchModuleName ) :
|
||||
m_pchModuleName( pchModuleName ),
|
||||
m_hModule( 0 ),
|
||||
m_bLoadAttempted( false )
|
||||
{
|
||||
}
|
||||
|
||||
CDllDemandLoader::~CDllDemandLoader()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
CreateInterfaceFn CDllDemandLoader::GetFactory()
|
||||
{
|
||||
if ( !m_hModule && !m_bLoadAttempted )
|
||||
{
|
||||
m_bLoadAttempted = true;
|
||||
m_hModule = Sys_LoadModule( m_pchModuleName );
|
||||
}
|
||||
|
||||
if ( !m_hModule )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Sys_GetFactory( m_hModule );
|
||||
}
|
||||
|
||||
void CDllDemandLoader::Unload()
|
||||
{
|
||||
if ( m_hModule )
|
||||
{
|
||||
Sys_UnloadModule( m_hModule );
|
||||
m_hModule = 0;
|
||||
}
|
||||
}
|
||||
3986
tier1/keyvalues.cpp
Normal file
3986
tier1/keyvalues.cpp
Normal file
File diff suppressed because it is too large
Load Diff
713
tier1/keyvaluesjson.cpp
Normal file
713
tier1/keyvaluesjson.cpp
Normal file
@@ -0,0 +1,713 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. =================//
|
||||
//
|
||||
// Read JSON-formatted data into KeyValues
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier1/keyvaluesjson.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
KeyValuesJSONParser::KeyValuesJSONParser( const CUtlBuffer &buf )
|
||||
{
|
||||
Init( (const char *)buf.Base(), buf.TellPut() );
|
||||
}
|
||||
|
||||
KeyValuesJSONParser::KeyValuesJSONParser( const char *pszText, int cbSize )
|
||||
{
|
||||
Init( pszText, cbSize >= 0 ? cbSize : V_strlen(pszText) );
|
||||
}
|
||||
|
||||
KeyValuesJSONParser::~KeyValuesJSONParser() {}
|
||||
|
||||
void KeyValuesJSONParser::Init( const char *pszText, int cbSize )
|
||||
{
|
||||
m_szErrMsg[0] = '\0';
|
||||
m_nLine = 1;
|
||||
m_cur = pszText;
|
||||
m_end = pszText+cbSize;
|
||||
|
||||
m_eToken = kToken_Null;
|
||||
NextToken();
|
||||
}
|
||||
|
||||
KeyValues *KeyValuesJSONParser::ParseFile()
|
||||
{
|
||||
// A valid JSON object should contain a single object, surrounded by curly braces.
|
||||
if ( m_eToken == kToken_EOF )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "Input contains no data" );
|
||||
return NULL;
|
||||
}
|
||||
if ( m_eToken == kToken_Err )
|
||||
return NULL;
|
||||
if ( m_eToken == '{' )
|
||||
{
|
||||
|
||||
// Parse the the entire file as one big object
|
||||
KeyValues *pResult = new KeyValues("");
|
||||
if ( !ParseObject( pResult ) )
|
||||
{
|
||||
pResult->deleteThis();
|
||||
return NULL;
|
||||
}
|
||||
if ( m_eToken == kToken_EOF )
|
||||
return pResult;
|
||||
pResult->deleteThis();
|
||||
}
|
||||
V_sprintf_safe( m_szErrMsg, "%s not expected here. A valid JSON document should be a single object, which begins with '{' and ends with '}'", GetTokenDebugText() );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool KeyValuesJSONParser::ParseObject( KeyValues *pObject )
|
||||
{
|
||||
Assert( m_eToken == '{' );
|
||||
int nOpenDelimLine = m_nLine;
|
||||
NextToken();
|
||||
KeyValues *pLastChild = NULL;
|
||||
while ( m_eToken != '}' )
|
||||
{
|
||||
// Parse error?
|
||||
if ( m_eToken == kToken_Err )
|
||||
return false;
|
||||
if ( m_eToken == kToken_EOF )
|
||||
{
|
||||
// Actually report the error at the line of the unmatched delimiter.
|
||||
// There's no need to report the line number of the end of file, that is always
|
||||
// useless.
|
||||
m_nLine = nOpenDelimLine;
|
||||
V_strcpy_safe( m_szErrMsg, "End of input was reached and '{' was not matched by '}'" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// It must be a string, for the key name
|
||||
if ( m_eToken != kToken_String )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "%s not expected here; expected string for key name or '}'", GetTokenDebugText() );
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyValues *pChildValue = new KeyValues( m_vecTokenChars.Base() );
|
||||
NextToken();
|
||||
|
||||
// Expect and eat colon
|
||||
if ( m_eToken != ':' )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "%s not expected here. Missing ':'?", GetTokenDebugText() );
|
||||
pChildValue->deleteThis();
|
||||
return false;
|
||||
}
|
||||
NextToken();
|
||||
|
||||
// Recursively parse the value
|
||||
if ( !ParseValue( pChildValue ) )
|
||||
{
|
||||
pChildValue->deleteThis();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add to parent.
|
||||
pObject->AddSubkeyUsingKnownLastChild( pChildValue, pLastChild );
|
||||
pLastChild = pChildValue;
|
||||
|
||||
// Eat the comma, if there is one. If no comma,
|
||||
// then the other thing that could come next
|
||||
// is the closing brace to close the object
|
||||
// NOTE: We are allowing the extra comma after the last item
|
||||
if ( m_eToken == ',' )
|
||||
{
|
||||
NextToken();
|
||||
}
|
||||
else if ( m_eToken != '}' )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "%s not expected here. Missing ',' or '}'?", GetTokenDebugText() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Eat closing '}'
|
||||
NextToken();
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyValuesJSONParser::ParseArray( KeyValues *pArray )
|
||||
{
|
||||
Assert( m_eToken == '[' );
|
||||
int nOpenDelimLine = m_nLine;
|
||||
NextToken();
|
||||
KeyValues *pLastChild = NULL;
|
||||
int idx = 0;
|
||||
while ( m_eToken != ']' )
|
||||
{
|
||||
// Parse error?
|
||||
if ( m_eToken == kToken_Err )
|
||||
return false;
|
||||
if ( m_eToken == kToken_EOF )
|
||||
{
|
||||
// Actually report the error at the line of the unmatched delimiter.
|
||||
// There's no need to report the line number of the end of file, that is always
|
||||
// useless.
|
||||
m_nLine = nOpenDelimLine;
|
||||
V_strcpy_safe( m_szErrMsg, "End of input was reached and '[' was not matched by ']'" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set a dummy key name based on the index
|
||||
char szKeyName[ 32 ];
|
||||
V_sprintf_safe( szKeyName, "%d", idx );
|
||||
++idx;
|
||||
KeyValues *pChildValue = new KeyValues( szKeyName );
|
||||
|
||||
// Recursively parse the value
|
||||
if ( !ParseValue( pChildValue ) )
|
||||
{
|
||||
pChildValue->deleteThis();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add to parent.
|
||||
pArray->AddSubkeyUsingKnownLastChild( pChildValue, pLastChild );
|
||||
pLastChild = pChildValue;
|
||||
|
||||
// Handle a colon here specially. If one appears, the odds are they
|
||||
// are trying to put object-like data inside of an array
|
||||
if ( m_eToken == ':' )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "':' not expected inside an array. ('[]' used when '{}' was intended?)" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Eat the comma, if there is one. If no comma,
|
||||
// then the other thing that could come next
|
||||
// is the closing brace to close the object
|
||||
// NOTE: We are allowing the extra comma after the last item
|
||||
if ( m_eToken == ',' )
|
||||
{
|
||||
NextToken();
|
||||
}
|
||||
else if ( m_eToken != ']' )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "%s not expected here. Missing ',' or ']'?", GetTokenDebugText() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Eat closing ']'
|
||||
NextToken();
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyValuesJSONParser::ParseValue( KeyValues *pValue )
|
||||
{
|
||||
switch ( m_eToken )
|
||||
{
|
||||
case '{': return ParseObject( pValue );
|
||||
case '[': return ParseArray( pValue );
|
||||
case kToken_String:
|
||||
pValue->SetString( NULL, m_vecTokenChars.Base() );
|
||||
NextToken();
|
||||
return true;
|
||||
|
||||
case kToken_NumberInt:
|
||||
{
|
||||
const char *pszNum = m_vecTokenChars.Base();
|
||||
|
||||
// Negative?
|
||||
if ( *pszNum == '-' )
|
||||
{
|
||||
int64 val64 = V_atoi64( pszNum );
|
||||
if ( val64 < INT32_MIN )
|
||||
{
|
||||
// !KLUDGE! KeyValues cannot support this!
|
||||
V_sprintf_safe( m_szErrMsg, "%s is out of range for KeyValues, which doesn't support signed 64-bit numbers", pszNum );
|
||||
return false;
|
||||
}
|
||||
|
||||
pValue->SetInt( NULL, (int)val64 );
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64 val64 = V_atoui64( pszNum );
|
||||
if ( val64 > 0x7fffffffU )
|
||||
{
|
||||
pValue->SetUint64( NULL, val64 );
|
||||
}
|
||||
else
|
||||
{
|
||||
pValue->SetInt( NULL, (int)val64 );
|
||||
}
|
||||
}
|
||||
NextToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
case kToken_NumberFloat:
|
||||
{
|
||||
float f = V_atof( m_vecTokenChars.Base() );
|
||||
pValue->SetFloat( NULL, f );
|
||||
NextToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
case kToken_True:
|
||||
pValue->SetBool( NULL, true );
|
||||
NextToken();
|
||||
return true;
|
||||
|
||||
case kToken_False:
|
||||
pValue->SetBool( NULL, false );
|
||||
NextToken();
|
||||
return true;
|
||||
|
||||
case kToken_Null:
|
||||
pValue->SetPtr( NULL, NULL );
|
||||
NextToken();
|
||||
return true;
|
||||
|
||||
case kToken_Err:
|
||||
return false;
|
||||
}
|
||||
|
||||
V_sprintf_safe( m_szErrMsg, "%s not expected here; missing value?", GetTokenDebugText() );
|
||||
return false;
|
||||
}
|
||||
|
||||
void KeyValuesJSONParser::NextToken()
|
||||
{
|
||||
|
||||
// Already in terminal state?
|
||||
if ( m_eToken < 0 )
|
||||
return;
|
||||
|
||||
// Clear token
|
||||
m_vecTokenChars.SetCount(0);
|
||||
|
||||
// Scan until we hit the end of input
|
||||
while ( m_cur < m_end )
|
||||
{
|
||||
|
||||
// Next character?
|
||||
char c = *m_cur;
|
||||
switch (c)
|
||||
{
|
||||
// Whitespace? Eat it and keep parsing
|
||||
case ' ':
|
||||
case '\t':
|
||||
++m_cur;
|
||||
break;
|
||||
|
||||
// Newline? Eat it and advance line number
|
||||
case '\n':
|
||||
case '\r':
|
||||
++m_nLine;
|
||||
++m_cur;
|
||||
|
||||
// Eat \r\n or \n\r pair as a single character
|
||||
if ( m_cur < m_end && *m_cur == ( '\n' + '\r' - c ) )
|
||||
++m_cur;
|
||||
break;
|
||||
|
||||
// Single-character JSON token?
|
||||
case ':':
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
case ']':
|
||||
case ',':
|
||||
m_eToken = c;
|
||||
++m_cur;
|
||||
return;
|
||||
|
||||
// String?
|
||||
case '\"':
|
||||
case '\'': // NOTE: We allow strings to be delimited by single quotes, which is not JSON compliant
|
||||
ParseStringToken();
|
||||
return;
|
||||
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
ParseNumberToken();
|
||||
return;
|
||||
|
||||
// Literal "true"
|
||||
case 't':
|
||||
if ( m_cur + 4 <= m_end && m_cur[1] == 'r' && m_cur[2] == 'u' && m_cur[3] == 'e' )
|
||||
{
|
||||
m_cur += 4;
|
||||
m_eToken = kToken_True;
|
||||
return;
|
||||
}
|
||||
goto unexpected_char;
|
||||
|
||||
// Literal "false"
|
||||
case 'f':
|
||||
if ( m_cur + 5 <= m_end && m_cur[1] == 'a' && m_cur[2] == 'l' && m_cur[3] == 's' && m_cur[4] == 'e' )
|
||||
{
|
||||
m_cur += 5;
|
||||
m_eToken = kToken_False;
|
||||
return;
|
||||
}
|
||||
goto unexpected_char;
|
||||
|
||||
// Literal "null"
|
||||
case 'n':
|
||||
if ( m_cur + 4 <= m_end && m_cur[1] == 'u' && m_cur[2] == 'l' && m_cur[3] == 'l' )
|
||||
{
|
||||
m_cur += 4;
|
||||
m_eToken = kToken_Null;
|
||||
return;
|
||||
}
|
||||
goto unexpected_char;
|
||||
|
||||
case '/':
|
||||
// C++-style comment?
|
||||
if ( m_cur < m_end && m_cur[1] == '/' )
|
||||
{
|
||||
m_cur += 2;
|
||||
while ( m_cur < m_end && *m_cur != '\n' && *m_cur != '\r' )
|
||||
++m_cur;
|
||||
// Leave newline as the next character, we'll handle it above
|
||||
break;
|
||||
}
|
||||
// | fall
|
||||
// | through
|
||||
// V
|
||||
|
||||
default:
|
||||
unexpected_char:
|
||||
if ( V_isprint(c) )
|
||||
V_sprintf_safe( m_szErrMsg, "Unexpected character 0x%02x ('%c')", (uint8)c, c );
|
||||
else
|
||||
V_sprintf_safe( m_szErrMsg, "Unexpected character 0x%02x", (uint8)c );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_eToken = kToken_EOF;
|
||||
}
|
||||
|
||||
void KeyValuesJSONParser::ParseNumberToken()
|
||||
{
|
||||
// Clear token
|
||||
m_vecTokenChars.SetCount(0);
|
||||
|
||||
// Eat leading minus sign
|
||||
if ( *m_cur == '-' )
|
||||
{
|
||||
m_vecTokenChars.AddToTail( '-' );
|
||||
++m_cur;
|
||||
}
|
||||
|
||||
if ( m_cur >= m_end )
|
||||
{
|
||||
V_strcpy_safe( m_szErrMsg, "Unexpected EOF while parsing number" );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
|
||||
char c = *m_cur;
|
||||
m_vecTokenChars.AddToTail( c );
|
||||
bool bHasWholePart = false;
|
||||
switch ( c )
|
||||
{
|
||||
case '0':
|
||||
// Leading 0 cannot be followed by any more digits, as per JSON spec (and to make sure nobody tries to parse octal).
|
||||
++m_cur;
|
||||
bHasWholePart = true;
|
||||
break;
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
bHasWholePart = true;
|
||||
++m_cur;
|
||||
|
||||
// Accumulate digits until we hit a non-digit
|
||||
while ( m_cur < m_end && *m_cur >= '0' && *m_cur <= '9' )
|
||||
m_vecTokenChars.AddToTail( *(m_cur++) );
|
||||
break;
|
||||
|
||||
case '.':
|
||||
// strict JSON doesn't allow a number that starts with a decimal point, but we do
|
||||
break;
|
||||
}
|
||||
|
||||
// Assume this is integral, unless we hit a decimal point and/or exponent
|
||||
m_eToken = kToken_NumberInt;
|
||||
|
||||
// Fractional portion?
|
||||
if ( m_cur < m_end && *m_cur == '.' )
|
||||
{
|
||||
m_eToken = kToken_NumberFloat;
|
||||
|
||||
// Eat decimal point
|
||||
m_vecTokenChars.AddToTail( *(m_cur++) );
|
||||
|
||||
// Accumulate digits until we hit a non-digit
|
||||
bool bHasFractionPart = false;
|
||||
while ( m_cur < m_end && *m_cur >= '0' && *m_cur <= '9' )
|
||||
{
|
||||
m_vecTokenChars.AddToTail( *(m_cur++) );
|
||||
bHasFractionPart = true;
|
||||
}
|
||||
|
||||
// Make sure we aren't just a single '.'
|
||||
if ( !bHasWholePart && !bHasFractionPart )
|
||||
{
|
||||
m_vecTokenChars.AddToTail(0);
|
||||
V_sprintf_safe( m_szErrMsg, "Invalid number starting with '%s'", m_vecTokenChars.Base() );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Exponent?
|
||||
if ( m_cur < m_end && ( *m_cur == 'e' || *m_cur == 'E' ) )
|
||||
{
|
||||
m_eToken = kToken_NumberFloat;
|
||||
|
||||
// Eat 'e'
|
||||
m_vecTokenChars.AddToTail( *(m_cur++) );
|
||||
|
||||
// Optional sign
|
||||
if ( m_cur < m_end && ( *m_cur == '-' || *m_cur == '+' ) )
|
||||
m_vecTokenChars.AddToTail( *(m_cur++) );
|
||||
|
||||
// Accumulate digits until we hit a non-digit
|
||||
bool bHasExponentDigit = false;
|
||||
while ( m_cur < m_end && *m_cur >= '0' && *m_cur <= '9' )
|
||||
{
|
||||
m_vecTokenChars.AddToTail( *(m_cur++) );
|
||||
bHasExponentDigit = true;
|
||||
}
|
||||
if ( !bHasExponentDigit )
|
||||
{
|
||||
V_strcpy_safe( m_szErrMsg, "Bad exponent in floating point number" );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// OK, We have parsed a valid number.
|
||||
// Terminate token
|
||||
m_vecTokenChars.AddToTail( '\0' );
|
||||
|
||||
// EOF? That's OK for now, at this lexical parsing level. We'll handle the error
|
||||
// at the higher parse level, when expecting a comma or closing delimiter
|
||||
if ( m_cur >= m_end )
|
||||
return;
|
||||
|
||||
// Is the next thing a valid character? This is the most common case.
|
||||
c = *m_cur;
|
||||
if ( V_isspace( c ) || c == ',' || c == '}' || c == ']' || c == '/' )
|
||||
return;
|
||||
|
||||
// Handle these guys as "tokens", to provide a slightly more meaningful error message
|
||||
if ( c == '[' || c == '{' )
|
||||
return;
|
||||
|
||||
// Anything else, treat the whole thing as an invalid numerical constant
|
||||
if ( V_isprint(c) )
|
||||
V_sprintf_safe( m_szErrMsg, "Number contains invalid character 0x%02x ('%c')", (uint8)c, c );
|
||||
else
|
||||
V_sprintf_safe( m_szErrMsg, "Number contains invalid character 0x%02x", (uint8)c );
|
||||
m_eToken = kToken_Err;
|
||||
}
|
||||
|
||||
void KeyValuesJSONParser::ParseStringToken()
|
||||
{
|
||||
char cDelim = *(m_cur++);
|
||||
|
||||
while ( m_cur < m_end )
|
||||
{
|
||||
char c = *(m_cur++);
|
||||
if ( c == '\r' || c == '\n' )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "Hit end of line before closing quote (%c)", c );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
if ( c == cDelim )
|
||||
{
|
||||
m_eToken = kToken_String;
|
||||
m_vecTokenChars.AddToTail( '\0' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Ordinary character? Just append it
|
||||
if ( c != '\\' )
|
||||
{
|
||||
m_vecTokenChars.AddToTail( c );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Escaped character.
|
||||
// End of string? We'll handle it above
|
||||
if ( m_cur >= m_end )
|
||||
continue;
|
||||
|
||||
// Check table of allowed escape characters
|
||||
switch (c)
|
||||
{
|
||||
case '\\':
|
||||
case '/':
|
||||
case '\'':
|
||||
case '\"': m_vecTokenChars.AddToTail( c ); break;
|
||||
case 'b': m_vecTokenChars.AddToTail( '\b' ); break;
|
||||
case 'f': m_vecTokenChars.AddToTail( '\f' ); break;
|
||||
case 'n': m_vecTokenChars.AddToTail( '\n' ); break;
|
||||
case 'r': m_vecTokenChars.AddToTail( '\r' ); break;
|
||||
case 't': m_vecTokenChars.AddToTail( '\t' ); break;
|
||||
|
||||
case 'u':
|
||||
{
|
||||
|
||||
// Make sure are followed by exactly 4 hex digits
|
||||
if ( m_cur + 4 > m_end || !V_isxdigit( m_cur[0] ) || !V_isxdigit( m_cur[1] ) || !V_isxdigit( m_cur[2] ) || !V_isxdigit( m_cur[3] ) )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "\\u must be followed by exactly 4 hex digits" );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the codepoint
|
||||
uchar32 nCodePoint = 0;
|
||||
for ( int n = 0 ; n < 4 ; ++n )
|
||||
{
|
||||
nCodePoint <<= 4;
|
||||
char chHex = *(m_cur++);
|
||||
if ( chHex >= '0' && chHex <= '9' )
|
||||
nCodePoint += chHex - '0';
|
||||
else if ( chHex >= 'a' && chHex <= 'a' )
|
||||
nCodePoint += chHex + 0x0a - 'a';
|
||||
else if ( chHex >= 'A' && chHex <= 'A' )
|
||||
nCodePoint += chHex + 0x0a - 'A';
|
||||
else
|
||||
Assert( false ); // inconceivable, due to above
|
||||
}
|
||||
|
||||
// Encode it in UTF-8
|
||||
char utf8Encode[8];
|
||||
int r = Q_UChar32ToUTF8( nCodePoint, utf8Encode );
|
||||
if ( r < 0 || r > 4 )
|
||||
{
|
||||
V_sprintf_safe( m_szErrMsg, "Invalid code point \\u%04x", nCodePoint );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
for ( int i = 0 ; i < r ; ++i )
|
||||
m_vecTokenChars.AddToTail( utf8Encode[i] );
|
||||
} break;
|
||||
|
||||
default:
|
||||
if ( V_isprint(c) )
|
||||
V_sprintf_safe( m_szErrMsg, "Invalid escape character 0x%02x ('\\%c')", (uint8)c, c );
|
||||
else
|
||||
V_sprintf_safe( m_szErrMsg, "Invalid escape character 0x%02x", (uint8)c );
|
||||
m_eToken = kToken_Err;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
V_sprintf_safe( m_szErrMsg, "Hit end of input before closing quote (%c)", cDelim );
|
||||
m_eToken = kToken_Err;
|
||||
}
|
||||
|
||||
const char *KeyValuesJSONParser::GetTokenDebugText()
|
||||
{
|
||||
switch ( m_eToken )
|
||||
{
|
||||
case kToken_EOF: return "<EOF>";
|
||||
case kToken_String: return "<string>";
|
||||
case kToken_NumberInt:
|
||||
case kToken_NumberFloat: return "<number>";
|
||||
case kToken_True: return "'true'";
|
||||
case kToken_False: return "'false'";
|
||||
case kToken_Null: return "'null'";
|
||||
case '{': return "'{'";
|
||||
case '}': return "'}'";
|
||||
case '[': return "'['";
|
||||
case ']': return "']'";
|
||||
case ':': return "':'";
|
||||
case ',': return "','";
|
||||
}
|
||||
|
||||
// We shouldn't ever need to ask for a debug string for the error token,
|
||||
// and anything else is an error
|
||||
Assert( false );
|
||||
return "<parse error>";
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
static void JSONTest_ParseValid( const char *pszData )
|
||||
{
|
||||
KeyValuesJSONParser parser( pszData );
|
||||
KeyValues *pFile = parser.ParseFile();
|
||||
Assert( pFile );
|
||||
pFile->deleteThis();
|
||||
}
|
||||
|
||||
static void JSONTest_ParseInvalid( const char *pszData, const char *pszExpectedErrMsgSnippet, int nExpectedFailureLine )
|
||||
{
|
||||
KeyValuesJSONParser parser( pszData );
|
||||
KeyValues *pFile = parser.ParseFile();
|
||||
Assert( pFile == NULL );
|
||||
Assert( V_stristr( parser.m_szErrMsg, pszExpectedErrMsgSnippet ) != NULL );
|
||||
Assert( parser.m_nLine == nExpectedFailureLine );
|
||||
}
|
||||
|
||||
void TestKeyValuesJSONParser()
|
||||
{
|
||||
JSONTest_ParseValid( "{}" );
|
||||
JSONTest_ParseValid( R"JSON({
|
||||
"key": "string_value",
|
||||
"pos_int32": 123,
|
||||
"pos_int64": 123456789012,
|
||||
"neg_int32": -456,
|
||||
"float": -45.23,
|
||||
"pos_exponent": 1e30,
|
||||
"neg_exponent": 1e-16,
|
||||
"decimal_and_exponent": 1.e+30,
|
||||
"no_leading_zero": .7, // we support this, even though strict JSON says it's no good
|
||||
"zero": 0,
|
||||
"true_value": true,
|
||||
"false_value": false,
|
||||
"null_value": null,
|
||||
"with_escaped": "\r \t \n",
|
||||
"unicode": "\u1234 \\u12f3",
|
||||
"array_of_ints": [ 1, 2, 3, -45 ],
|
||||
"empty_array": [],
|
||||
"array_with_stuff_inside": [
|
||||
{}, // this is a comment.
|
||||
[ 0.45, {}, "hello!" ],
|
||||
{ "id": 0 },
|
||||
// Trailing comma above. Comment here
|
||||
],
|
||||
})JSON" );
|
||||
JSONTest_ParseInvalid( "{ \"key\": 123", "missing", 1 );
|
||||
JSONTest_ParseInvalid( "{ \"key\": 123.4f }", "number", 1 );
|
||||
}
|
||||
|
||||
#endif
|
||||
285
tier1/kvpacker.cpp
Normal file
285
tier1/kvpacker.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
//========= Copyright (c), 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.PutPtr( 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();
|
||||
if ( nLength >= 0 && nLength*sizeof( uint16 ) <= (uint)buffer.GetBytesRemaining() )
|
||||
{
|
||||
if ( nLength > 0 )
|
||||
{
|
||||
wchar_t *pTemp = (wchar_t *)malloc( sizeof( wchar_t ) * (1 + nLength) );
|
||||
|
||||
for ( int k = 0; k < nLength; ++k )
|
||||
{
|
||||
pTemp[k] = buffer.GetShort(); // ugly, but preserving existing behavior
|
||||
}
|
||||
|
||||
pTemp[nLength] = 0;
|
||||
dat->SetWString( NULL, pTemp );
|
||||
|
||||
free( pTemp );
|
||||
}
|
||||
else
|
||||
dat->SetWString( NULL, L"" );
|
||||
|
||||
}
|
||||
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, buffer.GetPtr() );
|
||||
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();
|
||||
}
|
||||
|
||||
1220
tier1/lzmaDecoder.cpp
Normal file
1220
tier1/lzmaDecoder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
425
tier1/lzss.cpp
Normal file
425
tier1/lzss.cpp
Normal file
@@ -0,0 +1,425 @@
|
||||
//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// LZSS Codec. Designed for fast cheap gametime encoding/decoding. Compression results
|
||||
// are not aggresive as other alogrithms, but gets 2:1 on most arbitrary uncompressed data.
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/lzss.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
|
||||
#define LZSS_LOOKSHIFT 4
|
||||
#define LZSS_LOOKAHEAD ( 1 << LZSS_LOOKSHIFT )
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns true if buffer is compressed.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLZSS::IsCompressed( unsigned char *pInput )
|
||||
{
|
||||
lzss_header_t *pHeader = (lzss_header_t *)pInput;
|
||||
if ( pHeader && pHeader->id == LZSS_ID )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// unrecognized
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns uncompressed size of compressed input buffer. Used for allocating output
|
||||
// buffer for decompression. Returns 0 if input buffer is not compressed.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int CLZSS::GetActualSize( unsigned char *pInput )
|
||||
{
|
||||
lzss_header_t *pHeader = (lzss_header_t *)pInput;
|
||||
if ( pHeader && pHeader->id == LZSS_ID )
|
||||
{
|
||||
return LittleLong( pHeader->actualSize );
|
||||
}
|
||||
|
||||
// unrecognized
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CLZSS::BuildHash( unsigned char *pData )
|
||||
{
|
||||
lzss_list_t *pList;
|
||||
lzss_node_t *pTarget;
|
||||
|
||||
int targetindex = (unsigned int)( uintp( pData ) & 0xFFFFFFFF ) & ( m_nWindowSize - 1 );
|
||||
pTarget = &m_pHashTarget[targetindex];
|
||||
if ( pTarget->pData )
|
||||
{
|
||||
pList = &m_pHashTable[*pTarget->pData];
|
||||
if ( pTarget->pPrev )
|
||||
{
|
||||
pList->pEnd = pTarget->pPrev;
|
||||
pTarget->pPrev->pNext = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pList->pEnd = 0;
|
||||
pList->pStart = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pList = &m_pHashTable[*pData];
|
||||
pTarget->pData = pData;
|
||||
pTarget->pPrev = 0;
|
||||
pTarget->pNext = pList->pStart;
|
||||
if ( pList->pStart )
|
||||
{
|
||||
pList->pStart->pPrev = pTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
pList->pEnd = pTarget;
|
||||
}
|
||||
pList->pStart = pTarget;
|
||||
}
|
||||
|
||||
unsigned char *CLZSS::CompressNoAlloc( unsigned char *pInput, int inputLength, unsigned char *pOutputBuf, unsigned int *pOutputSize )
|
||||
{
|
||||
if ( inputLength <= sizeof( lzss_header_t ) + 8 )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create the compression work buffers, small enough (~64K) for stack
|
||||
m_pHashTable = (lzss_list_t *)stackalloc( 256 * sizeof( lzss_list_t ) );
|
||||
memset( m_pHashTable, 0, 256 * sizeof( lzss_list_t ) );
|
||||
m_pHashTarget = (lzss_node_t *)stackalloc( m_nWindowSize * sizeof( lzss_node_t ) );
|
||||
memset( m_pHashTarget, 0, m_nWindowSize * sizeof( lzss_node_t ) );
|
||||
|
||||
// allocate the output buffer, compressed buffer is expected to be less, caller will free
|
||||
unsigned char *pStart = pOutputBuf;
|
||||
// prevent compression failure (inflation), leave enough to allow dribble eof bytes
|
||||
unsigned char *pEnd = pStart + inputLength - sizeof ( lzss_header_t ) - 8;
|
||||
|
||||
// set the header
|
||||
lzss_header_t *pHeader = (lzss_header_t *)pStart;
|
||||
pHeader->id = LZSS_ID;
|
||||
pHeader->actualSize = LittleLong( inputLength );
|
||||
|
||||
unsigned char *pOutput = pStart + sizeof (lzss_header_t);
|
||||
unsigned char *pLookAhead = pInput;
|
||||
unsigned char *pWindow = pInput;
|
||||
unsigned char *pEncodedPosition = NULL;
|
||||
unsigned char *pCmdByte = NULL;
|
||||
int putCmdByte = 0;
|
||||
|
||||
while ( inputLength > 0 )
|
||||
{
|
||||
pWindow = pLookAhead - m_nWindowSize;
|
||||
if ( pWindow < pInput )
|
||||
{
|
||||
pWindow = pInput;
|
||||
}
|
||||
|
||||
if ( !putCmdByte )
|
||||
{
|
||||
pCmdByte = pOutput++;
|
||||
*pCmdByte = 0;
|
||||
}
|
||||
putCmdByte = ( putCmdByte + 1 ) & 0x07;
|
||||
|
||||
int encodedLength = 0;
|
||||
int lookAheadLength = inputLength < LZSS_LOOKAHEAD ? inputLength : LZSS_LOOKAHEAD;
|
||||
|
||||
lzss_node_t *pHash = m_pHashTable[pLookAhead[0]].pStart;
|
||||
while ( pHash )
|
||||
{
|
||||
int matchLength = 0;
|
||||
int length = lookAheadLength;
|
||||
while ( length-- && pHash->pData[matchLength] == pLookAhead[matchLength] )
|
||||
{
|
||||
matchLength++;
|
||||
}
|
||||
if ( matchLength > encodedLength )
|
||||
{
|
||||
encodedLength = matchLength;
|
||||
pEncodedPosition = pHash->pData;
|
||||
}
|
||||
if ( matchLength == lookAheadLength )
|
||||
{
|
||||
break;
|
||||
}
|
||||
pHash = pHash->pNext;
|
||||
}
|
||||
|
||||
if ( encodedLength >= 3 )
|
||||
{
|
||||
*pCmdByte = ( *pCmdByte >> 1 ) | 0x80;
|
||||
*pOutput++ = ( ( pLookAhead-pEncodedPosition-1 ) >> LZSS_LOOKSHIFT );
|
||||
*pOutput++ = ( ( pLookAhead-pEncodedPosition-1 ) << LZSS_LOOKSHIFT ) | ( encodedLength-1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
encodedLength = 1;
|
||||
*pCmdByte = ( *pCmdByte >> 1 );
|
||||
*pOutput++ = *pLookAhead;
|
||||
}
|
||||
|
||||
for ( int i=0; i<encodedLength; i++ )
|
||||
{
|
||||
BuildHash( pLookAhead++ );
|
||||
}
|
||||
|
||||
inputLength -= encodedLength;
|
||||
|
||||
if ( pOutput >= pEnd )
|
||||
{
|
||||
// compression is worse, abandon
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( inputLength != 0 )
|
||||
{
|
||||
// unexpected failure
|
||||
Assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !putCmdByte )
|
||||
{
|
||||
pCmdByte = pOutput++;
|
||||
*pCmdByte = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pCmdByte = ( ( *pCmdByte >> 1 ) | 0x80 ) >> ( 7 - putCmdByte );
|
||||
}
|
||||
|
||||
*pOutput++ = 0;
|
||||
*pOutput++ = 0;
|
||||
|
||||
if ( pOutputSize )
|
||||
{
|
||||
*pOutputSize = pOutput - pStart;
|
||||
}
|
||||
|
||||
return pStart;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compress an input buffer. Caller must free output compressed buffer.
|
||||
// Returns NULL if compression failed (i.e. compression yielded worse results)
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char* CLZSS::Compress( unsigned char *pInput, int inputLength, unsigned int *pOutputSize )
|
||||
{
|
||||
unsigned char *pStart = (unsigned char *)malloc( inputLength );
|
||||
unsigned char *pFinal = CompressNoAlloc( pInput, inputLength, pStart, pOutputSize );
|
||||
if ( !pFinal )
|
||||
{
|
||||
free( pStart );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pStart;
|
||||
}
|
||||
|
||||
/*
|
||||
// BUG BUG: This code is flaky, don't use until it's debugged!!!
|
||||
unsigned int CLZSS::Uncompress( unsigned char *pInput, CUtlBuffer &buf )
|
||||
{
|
||||
int cmdByte = 0;
|
||||
int getCmdByte = 0;
|
||||
|
||||
unsigned int actualSize = GetActualSize( pInput );
|
||||
if ( !actualSize )
|
||||
{
|
||||
// unrecognized
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *pBase = ( unsigned char * )buf.Base();
|
||||
|
||||
pInput += sizeof( lzss_header_t );
|
||||
|
||||
while ( !buf.IsValid() )
|
||||
{
|
||||
if ( !getCmdByte )
|
||||
{
|
||||
cmdByte = *pInput++;
|
||||
}
|
||||
getCmdByte = ( getCmdByte + 1 ) & 0x07;
|
||||
|
||||
if ( cmdByte & 0x01 )
|
||||
{
|
||||
int position = *pInput++ << LZSS_LOOKSHIFT;
|
||||
position |= ( *pInput >> LZSS_LOOKSHIFT );
|
||||
int count = ( *pInput++ & 0x0F ) + 1;
|
||||
if ( count == 1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
unsigned int pos = buf.TellPut();
|
||||
unsigned char *pSource = ( pBase + pos ) - position - 1;
|
||||
|
||||
// BUGBUG:
|
||||
// This is failing!!!
|
||||
// buf.WriteBytes( pSource, count );
|
||||
// So have to iterate them manually
|
||||
for ( int i =0; i < count; ++i )
|
||||
{
|
||||
buf.PutUnsignedChar( *pSource++ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutUnsignedChar( *pInput++ );
|
||||
}
|
||||
cmdByte = cmdByte >> 1;
|
||||
}
|
||||
|
||||
if ( buf.TellPut() != (int)actualSize )
|
||||
{
|
||||
// unexpected failure
|
||||
Assert( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buf.TellPut();
|
||||
}
|
||||
*/
|
||||
|
||||
unsigned int CLZSS::SafeUncompress( unsigned char *pInput, unsigned char *pOutput, unsigned int unBufSize )
|
||||
{
|
||||
unsigned int totalBytes = 0;
|
||||
int cmdByte = 0;
|
||||
int getCmdByte = 0;
|
||||
|
||||
unsigned int actualSize = GetActualSize( pInput );
|
||||
if ( !actualSize )
|
||||
{
|
||||
// unrecognized
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( actualSize > unBufSize )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pInput += sizeof( lzss_header_t );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( !getCmdByte )
|
||||
{
|
||||
cmdByte = *pInput++;
|
||||
}
|
||||
getCmdByte = ( getCmdByte + 1 ) & 0x07;
|
||||
|
||||
if ( cmdByte & 0x01 )
|
||||
{
|
||||
int position = *pInput++ << LZSS_LOOKSHIFT;
|
||||
position |= ( *pInput >> LZSS_LOOKSHIFT );
|
||||
int count = ( *pInput++ & 0x0F ) + 1;
|
||||
if ( count == 1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
unsigned char *pSource = pOutput - position - 1;
|
||||
|
||||
if ( totalBytes + count > unBufSize )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( int i=0; i<count; i++ )
|
||||
{
|
||||
*pOutput++ = *pSource++;
|
||||
}
|
||||
totalBytes += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( totalBytes + 1 > unBufSize )
|
||||
return 0;
|
||||
|
||||
*pOutput++ = *pInput++;
|
||||
totalBytes++;
|
||||
}
|
||||
cmdByte = cmdByte >> 1;
|
||||
}
|
||||
|
||||
if ( totalBytes != actualSize )
|
||||
{
|
||||
// unexpected failure
|
||||
Assert( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Uncompress a buffer, Returns the uncompressed size. Caller must provide an
|
||||
// adequate sized output buffer or memory corruption will occur.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int CLZSS::Uncompress( unsigned char *pInput, unsigned char *pOutput )
|
||||
{
|
||||
unsigned int totalBytes = 0;
|
||||
int cmdByte = 0;
|
||||
int getCmdByte = 0;
|
||||
|
||||
unsigned int actualSize = GetActualSize( pInput );
|
||||
if ( !actualSize )
|
||||
{
|
||||
// unrecognized
|
||||
return 0;
|
||||
}
|
||||
|
||||
pInput += sizeof( lzss_header_t );
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if ( !getCmdByte )
|
||||
{
|
||||
cmdByte = *pInput++;
|
||||
}
|
||||
getCmdByte = ( getCmdByte + 1 ) & 0x07;
|
||||
|
||||
if ( cmdByte & 0x01 )
|
||||
{
|
||||
int position = *pInput++ << LZSS_LOOKSHIFT;
|
||||
position |= ( *pInput >> LZSS_LOOKSHIFT );
|
||||
int count = ( *pInput++ & 0x0F ) + 1;
|
||||
if ( count == 1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
unsigned char *pSource = pOutput - position - 1;
|
||||
for ( int i=0; i<count; i++ )
|
||||
{
|
||||
*pOutput++ = *pSource++;
|
||||
}
|
||||
totalBytes += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pOutput++ = *pInput++;
|
||||
totalBytes++;
|
||||
}
|
||||
cmdByte = cmdByte >> 1;
|
||||
}
|
||||
|
||||
if ( totalBytes != actualSize )
|
||||
{
|
||||
// unexpected failure
|
||||
Assert( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
|
||||
10
tier1/memoverride_dummy.cpp
Normal file
10
tier1/memoverride_dummy.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
//========== Copyright © 2008, Valve Corporation, All rights reserved. ========
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
// This exists to allow projects that aren't built with memoverride.cpp to still link
|
||||
// even if USE_MEMDEBUG is enabled [12/1/2009 tom]
|
||||
|
||||
const char *g_pszModule = "memoverride not present";
|
||||
347
tier1/mempool.cpp
Normal file
347
tier1/mempool.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier1/mempool.h"
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "tier0/dbg.h"
|
||||
#include <ctype.h>
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
#ifndef _PS3
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is an allocation within the pool?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CUtlMemoryPool::IsAllocationWithinPool( void *pMem ) const
|
||||
{
|
||||
for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pCur->m_pNext )
|
||||
{
|
||||
// Is the allocation within the blob?
|
||||
if ( ( pMem < pCur->m_Data ) || ( pMem >= pCur->m_Data + pCur->m_NumBytes ) )
|
||||
continue;
|
||||
|
||||
// Make sure the allocation is on a block boundary
|
||||
intp pFirstAllocation = AlignValue( ( intp ) pCur->m_Data, m_nAlignment );
|
||||
|
||||
intp nOffset = (intp)pMem - pFirstAllocation;
|
||||
return ( nOffset % m_BlockSize ) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reports memory leaks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::ReportLeaks()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!g_ReportFunc)
|
||||
return;
|
||||
|
||||
g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated);
|
||||
|
||||
// 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 && V_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 > (size_t)m_BlockSize )
|
||||
return NULL;
|
||||
|
||||
if ( !m_pHeadOfFreeList )
|
||||
{
|
||||
// returning NULL is fine in GROW_NONE
|
||||
if ( m_GrowMode == GROW_NONE && m_NumBlobs > 0 )
|
||||
{
|
||||
//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, ( int )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;
|
||||
}
|
||||
|
||||
int CUtlMemoryPool::Size() const
|
||||
{
|
||||
uint32 size = 0;
|
||||
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
size += pCur->m_NumBytes;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
708
tier1/memstack.cpp
Normal file
708
tier1/memstack.cpp
Normal file
@@ -0,0 +1,708 @@
|
||||
//========= Copyright <20> 1996-2005, 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)
|
||||
#elif defined( _PS3 )
|
||||
#include "sys/memory.h"
|
||||
#include "sys/mempool.h"
|
||||
#include "sys/process.h"
|
||||
#include <sys/vm.h>
|
||||
#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
|
||||
|
||||
static volatile bool bSpewAllocations = false; // TODO: Register CMemoryStacks with g_pMemAlloc, so it can spew a summary
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
MEMALLOC_DEFINE_EXTERNAL_TRACKING(CMemoryStack);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PrintStatus( void* p )
|
||||
{
|
||||
CMemoryStack* pMemoryStack = (CMemoryStack*)p;
|
||||
|
||||
pMemoryStack->PrintContents();
|
||||
}
|
||||
|
||||
CMemoryStack::CMemoryStack()
|
||||
: m_pNextAlloc( NULL )
|
||||
, m_pCommitLimit( NULL )
|
||||
, m_pAllocLimit( NULL )
|
||||
, m_pHighestAllocLimit( NULL )
|
||||
, m_pBase( NULL )
|
||||
, m_bRegisteredAllocation( false )
|
||||
, m_maxSize( 0 )
|
||||
, m_alignment( 16 )
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
, m_commitIncrement( 0 )
|
||||
, m_minCommit( 0 )
|
||||
#ifdef _PS3
|
||||
, m_pVirtualMemorySection( NULL )
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
AddMemoryInfoCallback( this );
|
||||
m_pszAllocOwner = strdup( "CMemoryStack unattributed" );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
CMemoryStack::~CMemoryStack()
|
||||
{
|
||||
if ( m_pBase )
|
||||
Term();
|
||||
|
||||
RemoveMemoryInfoCallback( this );
|
||||
free( m_pszAllocOwner );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::Init( const char *pszAllocOwner, unsigned maxSize, unsigned commitIncrement, unsigned initialCommit, unsigned alignment )
|
||||
{
|
||||
Assert( !m_pBase );
|
||||
|
||||
m_bPhysical = false;
|
||||
|
||||
m_maxSize = maxSize;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
Assert( m_alignment == alignment );
|
||||
Assert( m_maxSize > 0 );
|
||||
|
||||
SetAllocOwner( pszAllocOwner );
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
|
||||
#ifdef _PS3
|
||||
// Memory can only be committed in page-size increments on PS3
|
||||
static const unsigned PS3_PAGE_SIZE = 64*1024;
|
||||
if ( commitSize < PS3_PAGE_SIZE )
|
||||
commitSize = PS3_PAGE_SIZE;
|
||||
#endif
|
||||
|
||||
if ( commitIncrement != 0 )
|
||||
{
|
||||
m_commitIncrement = commitIncrement;
|
||||
}
|
||||
|
||||
unsigned pageSize;
|
||||
|
||||
#ifdef _PS3
|
||||
pageSize = PS3_PAGE_SIZE;
|
||||
#elif defined( _X360 )
|
||||
pageSize = 64 * 1024;
|
||||
#else
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo( &sysInfo );
|
||||
Assert( !( sysInfo.dwPageSize & (sysInfo.dwPageSize-1)) );
|
||||
pageSize = sysInfo.dwPageSize;
|
||||
#endif
|
||||
|
||||
if ( m_commitIncrement == 0 )
|
||||
{
|
||||
m_commitIncrement = pageSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_commitIncrement = AlignValue( m_commitIncrement, pageSize );
|
||||
}
|
||||
|
||||
m_maxSize = AlignValue( m_maxSize, m_commitIncrement );
|
||||
|
||||
Assert( m_maxSize % pageSize == 0 && m_commitIncrement % pageSize == 0 && m_commitIncrement <= m_maxSize );
|
||||
|
||||
#ifdef _WIN32
|
||||
m_pBase = (unsigned char *)VirtualAlloc( NULL, m_maxSize, VA_RESERVE_FLAGS, PAGE_NOACCESS );
|
||||
#else
|
||||
m_pVirtualMemorySection = g_pMemAlloc->AllocateVirtualMemorySection( m_maxSize );
|
||||
if ( !m_pVirtualMemorySection )
|
||||
{
|
||||
Warning( "AllocateVirtualMemorySection failed( size=%d )\n", m_maxSize );
|
||||
Assert( 0 );
|
||||
m_pBase = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pBase = ( byte* ) m_pVirtualMemorySection->GetBaseAddress();
|
||||
}
|
||||
#endif
|
||||
if ( !m_pBase )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
m_pCommitLimit = m_pNextAlloc = m_pBase;
|
||||
|
||||
if ( initialCommit )
|
||||
{
|
||||
initialCommit = AlignValue( initialCommit, m_commitIncrement );
|
||||
Assert( initialCommit <= m_maxSize );
|
||||
bool bInitialCommitSucceeded = false;
|
||||
#ifdef _WIN32
|
||||
bInitialCommitSucceeded = !!VirtualAlloc( m_pCommitLimit, initialCommit, VA_COMMIT_FLAGS, PAGE_READWRITE );
|
||||
#else
|
||||
m_pVirtualMemorySection->CommitPages( m_pCommitLimit, initialCommit );
|
||||
bInitialCommitSucceeded = true;
|
||||
#endif
|
||||
if ( !bInitialCommitSucceeded )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory( initialCommit );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
m_minCommit = initialCommit;
|
||||
m_pCommitLimit += initialCommit;
|
||||
RegisterAllocation();
|
||||
}
|
||||
|
||||
#else
|
||||
m_pBase = (byte*)MemAlloc_AllocAligned( m_maxSize, alignment ? alignment : 1 );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
#endif
|
||||
|
||||
m_pHighestAllocLimit = m_pNextAlloc;
|
||||
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
#ifdef _GAMECONSOLE
|
||||
bool CMemoryStack::InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment, uint32 nFlags )
|
||||
{
|
||||
m_bPhysical = true;
|
||||
|
||||
m_maxSize = m_commitIncrement = size;
|
||||
m_alignment = AlignValue( alignment, 4 );
|
||||
|
||||
SetAllocOwner( pszAllocOwner );
|
||||
|
||||
#ifdef _X360
|
||||
int flags = PAGE_READWRITE | nFlags;
|
||||
if ( size >= 16*1024*1024 )
|
||||
{
|
||||
flags |= MEM_16MB_PAGES;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags |= MEM_LARGE_PAGES;
|
||||
}
|
||||
m_pBase = (unsigned char *)XPhysicalAlloc( m_maxSize, MAXULONG_PTR, nBaseAddrAlignment, flags );
|
||||
#elif defined (_PS3)
|
||||
m_pBase = (byte*)nFlags;
|
||||
m_pBase = (byte*)AlignValue( (uintp)m_pBase, m_alignment );
|
||||
#else
|
||||
#pragma error
|
||||
#endif
|
||||
|
||||
Assert( m_pBase );
|
||||
m_pNextAlloc = m_pBase;
|
||||
m_pCommitLimit = m_pBase + m_maxSize;
|
||||
m_pAllocLimit = m_pBase + m_maxSize;
|
||||
m_pHighestAllocLimit = m_pNextAlloc;
|
||||
|
||||
RegisterAllocation();
|
||||
return ( m_pBase != NULL );
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Term()
|
||||
{
|
||||
FreeAll();
|
||||
if ( m_pBase )
|
||||
{
|
||||
#ifdef _GAMECONSOLE
|
||||
if ( m_bPhysical )
|
||||
{
|
||||
#if defined( _X360 )
|
||||
XPhysicalFree( m_pBase );
|
||||
#elif defined( _PS3 )
|
||||
#else
|
||||
#pragma error
|
||||
#endif
|
||||
m_pCommitLimit = m_pBase = NULL;
|
||||
m_maxSize = 0;
|
||||
RegisterDeallocation(true);
|
||||
m_bPhysical = false;
|
||||
return;
|
||||
}
|
||||
#endif // _GAMECONSOLE
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
#if defined(_WIN32)
|
||||
VirtualFree( m_pBase, 0, MEM_RELEASE );
|
||||
#else
|
||||
m_pVirtualMemorySection->Release();
|
||||
m_pVirtualMemorySection = NULL;
|
||||
#endif
|
||||
#else
|
||||
MemAlloc_FreeAligned( m_pBase );
|
||||
#endif
|
||||
m_pBase = NULL;
|
||||
// Zero these variables to avoid getting misleading mem_dump
|
||||
// results when m_pBase is NULL.
|
||||
m_pNextAlloc = NULL;
|
||||
m_pCommitLimit = NULL;
|
||||
m_pHighestAllocLimit = NULL;
|
||||
m_maxSize = 0;
|
||||
RegisterDeallocation(true);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
int CMemoryStack::GetSize() const
|
||||
{
|
||||
if ( m_bPhysical )
|
||||
return m_maxSize;
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
return m_pCommitLimit - m_pBase;
|
||||
#else
|
||||
return m_maxSize;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
bool CMemoryStack::CommitTo( byte *pNextAlloc ) RESTRICT
|
||||
{
|
||||
if ( m_bPhysical )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
unsigned char * pNewCommitLimit = AlignValue( pNextAlloc, m_commitIncrement );
|
||||
ptrdiff_t commitIncrement = pNewCommitLimit - m_pCommitLimit;
|
||||
|
||||
if( m_pCommitLimit + commitIncrement > m_pAllocLimit )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory( commitIncrement );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( pNewCommitLimit > m_pCommitLimit )
|
||||
{
|
||||
RegisterDeallocation(false);
|
||||
bool bAllocationSucceeded = false;
|
||||
#ifdef _WIN32
|
||||
bAllocationSucceeded = !!VirtualAlloc( m_pCommitLimit, commitIncrement, VA_COMMIT_FLAGS, PAGE_READWRITE );
|
||||
#else
|
||||
bAllocationSucceeded = m_pVirtualMemorySection->CommitPages( m_pCommitLimit, commitIncrement );
|
||||
#endif
|
||||
if ( !bAllocationSucceeded )
|
||||
{
|
||||
#if !defined( NO_MALLOC_OVERRIDE )
|
||||
g_pMemAlloc->OutOfMemory( commitIncrement );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
m_pCommitLimit = pNewCommitLimit;
|
||||
|
||||
RegisterAllocation();
|
||||
}
|
||||
else if ( pNewCommitLimit < m_pCommitLimit )
|
||||
{
|
||||
if ( m_pNextAlloc > pNewCommitLimit )
|
||||
{
|
||||
Warning( "ATTEMPTED TO DECOMMIT OWNED MEMORY STACK SPACE\n" );
|
||||
pNewCommitLimit = AlignValue( m_pNextAlloc, m_commitIncrement );
|
||||
}
|
||||
|
||||
if ( pNewCommitLimit < m_pCommitLimit )
|
||||
{
|
||||
RegisterDeallocation(false);
|
||||
ptrdiff_t decommitIncrement = m_pCommitLimit - pNewCommitLimit;
|
||||
#ifdef _WIN32
|
||||
VirtualFree( pNewCommitLimit, decommitIncrement, MEM_DECOMMIT );
|
||||
#else
|
||||
m_pVirtualMemorySection->DecommitPages( pNewCommitLimit, decommitIncrement );
|
||||
#endif
|
||||
m_pCommitLimit = pNewCommitLimit;
|
||||
RegisterAllocation();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Identify the owner of this memory stack's memory
|
||||
void CMemoryStack::SetAllocOwner( const char *pszAllocOwner )
|
||||
{
|
||||
if ( !pszAllocOwner || !Q_strcmp( m_pszAllocOwner, pszAllocOwner ) )
|
||||
return;
|
||||
free( m_pszAllocOwner );
|
||||
m_pszAllocOwner = strdup( pszAllocOwner );
|
||||
}
|
||||
|
||||
void CMemoryStack::RegisterAllocation()
|
||||
{
|
||||
// 'physical' allocations on PS3 come from RSX local memory, so we don't count them here:
|
||||
if ( IsPS3() && m_bPhysical )
|
||||
return;
|
||||
|
||||
if ( GetSize() )
|
||||
{
|
||||
if ( m_bRegisteredAllocation )
|
||||
Warning( "CMemoryStack: ERROR - mismatched RegisterAllocation/RegisterDeallocation!\n" );
|
||||
|
||||
// NOTE: we deliberately don't use MemAlloc_RegisterExternalAllocation. CMemoryStack needs to bypass 'GetActualDbgInfo'
|
||||
// due to the way it allocates memory: there's just one representative memory address (m_pBase), it grows at unpredictable
|
||||
// times (in CommitTo, not every Alloc call) and it is freed en-masse (instead of freeing each individual allocation).
|
||||
MemAlloc_RegisterAllocation( m_pszAllocOwner, 0, GetSize(), GetSize(), 0 );
|
||||
}
|
||||
m_bRegisteredAllocation = true;
|
||||
|
||||
// Temp memorystack spew: very useful when we crash out of memory
|
||||
if ( IsGameConsole() && bSpewAllocations ) Msg( "CMemoryStack: %4.1fMB (%s)\n", GetSize()/(float)(1024*1024), m_pszAllocOwner );
|
||||
}
|
||||
|
||||
void CMemoryStack::RegisterDeallocation( bool bShouldSpewSize )
|
||||
{
|
||||
// 'physical' allocations on PS3 come from RSX local memory, so we don't count them here:
|
||||
if ( IsPS3() && m_bPhysical )
|
||||
return;
|
||||
|
||||
if ( GetSize() )
|
||||
{
|
||||
if ( !m_bRegisteredAllocation )
|
||||
Warning( "CMemoryStack: ERROR - mismatched RegisterAllocation/RegisterDeallocation!\n" );
|
||||
MemAlloc_RegisterDeallocation( m_pszAllocOwner, 0, GetSize(), GetSize(), 0 );
|
||||
}
|
||||
m_bRegisteredAllocation = false;
|
||||
|
||||
// Temp memorystack spew: very useful when we crash out of memory
|
||||
if ( bShouldSpewSize && IsGameConsole() && bSpewAllocations ) Msg( "CMemoryStack: %4.1fMB (%s)\n", GetSize()/(float)(1024*1024), m_pszAllocOwner );
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit )
|
||||
{
|
||||
mark = AlignValue( mark, m_alignment );
|
||||
byte *pAllocPoint = m_pBase + mark;
|
||||
|
||||
Assert( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc );
|
||||
if ( pAllocPoint >= m_pBase && pAllocPoint <= m_pNextAlloc )
|
||||
{
|
||||
m_pNextAlloc = pAllocPoint;
|
||||
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
|
||||
if ( bDecommit && !m_bPhysical )
|
||||
{
|
||||
CommitTo( MAX( m_pNextAlloc, (m_pBase + m_minCommit) ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::FreeAll( bool bDecommit )
|
||||
{
|
||||
if ( m_pBase && ( m_pBase < m_pCommitLimit ) )
|
||||
{
|
||||
FreeToAllocPoint( 0, bDecommit );
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::Access( void **ppRegion, unsigned *pBytes )
|
||||
{
|
||||
*ppRegion = m_pBase;
|
||||
*pBytes = ( m_pNextAlloc - m_pBase);
|
||||
}
|
||||
|
||||
const char* CMemoryStack::GetMemoryName() const
|
||||
{
|
||||
return m_pszAllocOwner;
|
||||
}
|
||||
|
||||
size_t CMemoryStack::GetAllocatedBytes() const
|
||||
{
|
||||
return GetUsed();
|
||||
}
|
||||
|
||||
size_t CMemoryStack::GetCommittedBytes() const
|
||||
{
|
||||
return GetSize();
|
||||
}
|
||||
|
||||
size_t CMemoryStack::GetReservedBytes() const
|
||||
{
|
||||
return GetMaxSize();
|
||||
}
|
||||
|
||||
size_t CMemoryStack::GetHighestBytes() const
|
||||
{
|
||||
size_t highest = m_pHighestAllocLimit - m_pBase;
|
||||
return highest;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CMemoryStack::PrintContents() const
|
||||
{
|
||||
size_t highest = m_pHighestAllocLimit - m_pBase;
|
||||
#ifdef PLATFORM_WINDOWS_PC
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
char moduleName[260];
|
||||
strcpy( moduleName, "unknown module" );
|
||||
// Because this code is statically linked into each DLL, this function and the PrintStatus
|
||||
// function will be in the DLL that constructed the CMemoryStack object. We can then
|
||||
// retrieve the DLL name to give slightly more verbose memory dumps.
|
||||
if ( VirtualQuery( &PrintStatus, &info, sizeof( info ) ) == sizeof( info ) )
|
||||
{
|
||||
GetModuleFileName( (HMODULE) info.AllocationBase, moduleName, _countof( moduleName ) );
|
||||
moduleName[ _countof( moduleName )-1 ] = 0;
|
||||
}
|
||||
Msg( "CMemoryStack %s in %s\n", m_pszAllocOwner, moduleName );
|
||||
#else
|
||||
Msg( "CMemoryStack %s\n", m_pszAllocOwner );
|
||||
#endif
|
||||
Msg( " Total used memory: %d KB\n", GetUsed() / 1024 );
|
||||
Msg( " Total committed memory: %d KB\n", GetSize() / 1024 );
|
||||
Msg( " Max committed memory: %u KB out of %d KB\n", (unsigned)highest / 1024, GetMaxSize() / 1024 );
|
||||
}
|
||||
|
||||
#ifdef _X360
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// A memory stack used for allocating physical memory on the 360 (can't commit/decommit)
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
MEMALLOC_DEFINE_EXTERNAL_TRACKING(CPhysicalMemoryStack);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CPhysicalMemoryStack::CPhysicalMemoryStack() :
|
||||
m_nAlignment( 16 ), m_nAdditionalFlags( 0 ), m_nUsage( 0 ), m_nPeakUsage( 0 ), m_pLastAllocedChunk( NULL ),
|
||||
m_nFirstAvailableChunk( 0 ), m_nChunkSizeInBytes( 0 ), m_ExtraChunks( 32, 32 ), m_nFramePeakUsage( 0 )
|
||||
{
|
||||
m_InitialChunk.m_pBase = NULL;
|
||||
m_InitialChunk.m_pNextAlloc = NULL;
|
||||
m_InitialChunk.m_pAllocLimit = NULL;
|
||||
}
|
||||
|
||||
CPhysicalMemoryStack::~CPhysicalMemoryStack()
|
||||
{
|
||||
Term();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Init, shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPhysicalMemoryStack::Init( size_t nChunkSizeInBytes, size_t nAlignment, int nInitialChunkCount, uint32 nAdditionalFlags )
|
||||
{
|
||||
Assert( !m_InitialChunk.m_pBase );
|
||||
|
||||
m_pLastAllocedChunk = NULL;
|
||||
m_nAdditionalFlags = nAdditionalFlags;
|
||||
m_nFirstAvailableChunk = 0;
|
||||
m_nUsage = 0;
|
||||
m_nFramePeakUsage = 0;
|
||||
m_nPeakUsage = 0;
|
||||
m_nAlignment = AlignValue( nAlignment, 4 );
|
||||
|
||||
// Chunk size must be aligned to the 360 page size
|
||||
size_t nInitMemorySize = nChunkSizeInBytes * nInitialChunkCount;
|
||||
nChunkSizeInBytes = AlignValue( nChunkSizeInBytes, 64 * 1024 );
|
||||
m_nChunkSizeInBytes = nChunkSizeInBytes;
|
||||
|
||||
// Fix up initial chunk count to get at least as much memory as requested
|
||||
// based on changes to the chunk size owing to page alignment issues
|
||||
nInitialChunkCount = ( nInitMemorySize + nChunkSizeInBytes - 1 ) / nChunkSizeInBytes;
|
||||
|
||||
int nFlags = PAGE_READWRITE | nAdditionalFlags;
|
||||
int nAllocationSize = m_nChunkSizeInBytes * nInitialChunkCount;
|
||||
if ( nAllocationSize >= 16*1024*1024 )
|
||||
{
|
||||
nFlags |= MEM_16MB_PAGES;
|
||||
}
|
||||
else
|
||||
{
|
||||
nFlags |= MEM_LARGE_PAGES;
|
||||
}
|
||||
m_InitialChunk.m_pBase = (uint8*)XPhysicalAlloc( nAllocationSize, MAXULONG_PTR, 0, nFlags );
|
||||
if ( !m_InitialChunk.m_pBase )
|
||||
{
|
||||
m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pAllocLimit = NULL;
|
||||
g_pMemAlloc->OutOfMemory();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pBase;
|
||||
m_InitialChunk.m_pAllocLimit = m_InitialChunk.m_pBase + nAllocationSize;
|
||||
|
||||
MemAlloc_RegisterExternalAllocation( CPhysicalMemoryStack, m_InitialChunk.m_pBase, XPhysicalSize( m_InitialChunk.m_pBase ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPhysicalMemoryStack::Term()
|
||||
{
|
||||
FreeAll();
|
||||
if ( m_InitialChunk.m_pBase )
|
||||
{
|
||||
MemAlloc_RegisterExternalDeallocation( CPhysicalMemoryStack, m_InitialChunk.m_pBase, XPhysicalSize( m_InitialChunk.m_pBase ) );
|
||||
XPhysicalFree( m_InitialChunk.m_pBase );
|
||||
m_InitialChunk.m_pBase = m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pAllocLimit = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the total allocation size
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t CPhysicalMemoryStack::GetSize() const
|
||||
{
|
||||
size_t nBaseSize = (intp)m_InitialChunk.m_pAllocLimit - (intp)m_InitialChunk.m_pBase;
|
||||
return nBaseSize + m_nChunkSizeInBytes * m_ExtraChunks.Count();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Allocate from the 'overflow' buffers, only happens if the initial allocation
|
||||
// isn't good enough
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CPhysicalMemoryStack::AllocFromOverflow( size_t nSizeInBytes )
|
||||
{
|
||||
// Completely full chunks are moved to the front and skipped
|
||||
int nCount = m_ExtraChunks.Count();
|
||||
for ( int i = m_nFirstAvailableChunk; i < nCount; ++i )
|
||||
{
|
||||
PhysicalChunk_t &chunk = m_ExtraChunks[i];
|
||||
|
||||
// Here we can check if a chunk is full and move it to the head
|
||||
// of the list. We can't do it immediately *after* allocation
|
||||
// because something may later free up some of the memory
|
||||
if ( chunk.m_pNextAlloc == chunk.m_pAllocLimit )
|
||||
{
|
||||
if ( i > 0 )
|
||||
{
|
||||
m_ExtraChunks.FastRemove( i );
|
||||
m_ExtraChunks.InsertBefore( 0 );
|
||||
}
|
||||
++m_nFirstAvailableChunk;
|
||||
continue;
|
||||
}
|
||||
|
||||
void *pResult = chunk.m_pNextAlloc;
|
||||
uint8 *pNextAlloc = chunk.m_pNextAlloc + nSizeInBytes;
|
||||
if ( pNextAlloc > chunk.m_pAllocLimit )
|
||||
continue;
|
||||
|
||||
chunk.m_pNextAlloc = pNextAlloc;
|
||||
m_pLastAllocedChunk = &chunk;
|
||||
return pResult;
|
||||
}
|
||||
|
||||
// No extra chunks to use; add a new one
|
||||
int i = m_ExtraChunks.AddToTail();
|
||||
PhysicalChunk_t &chunk = m_ExtraChunks[i];
|
||||
|
||||
int nFlags = PAGE_READWRITE | MEM_LARGE_PAGES | m_nAdditionalFlags;
|
||||
chunk.m_pBase = (uint8*)XPhysicalAlloc( m_nChunkSizeInBytes, MAXULONG_PTR, 0, nFlags );
|
||||
if ( !chunk.m_pBase )
|
||||
{
|
||||
chunk.m_pNextAlloc = chunk.m_pAllocLimit = NULL;
|
||||
m_pLastAllocedChunk = NULL;
|
||||
g_pMemAlloc->OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
MemAlloc_RegisterExternalAllocation( CPhysicalMemoryStack, chunk.m_pBase, XPhysicalSize( chunk.m_pBase ) );
|
||||
|
||||
m_pLastAllocedChunk = &chunk;
|
||||
chunk.m_pNextAlloc = chunk.m_pBase + nSizeInBytes;
|
||||
chunk.m_pAllocLimit = chunk.m_pBase + m_nChunkSizeInBytes;
|
||||
return chunk.m_pBase;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Allows us to free a portion of the previous allocation
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPhysicalMemoryStack::FreeToAllocPoint( MemoryStackMark_t mark, bool bUnused )
|
||||
{
|
||||
mark = AlignValue( mark, m_nAlignment );
|
||||
uint8 *pAllocPoint = m_pLastAllocedChunk->m_pBase + mark;
|
||||
Assert( pAllocPoint >= m_pLastAllocedChunk->m_pBase && pAllocPoint <= m_pLastAllocedChunk->m_pNextAlloc );
|
||||
if ( pAllocPoint >= m_pLastAllocedChunk->m_pBase && pAllocPoint <= m_pLastAllocedChunk->m_pNextAlloc )
|
||||
{
|
||||
m_nUsage -= (intp)m_pLastAllocedChunk->m_pNextAlloc - (intp)pAllocPoint;
|
||||
m_pLastAllocedChunk->m_pNextAlloc = pAllocPoint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Free overflow buffers, mark initial buffer as empty
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPhysicalMemoryStack::FreeAll( bool bUnused )
|
||||
{
|
||||
m_nUsage = 0;
|
||||
m_nFramePeakUsage = 0;
|
||||
m_InitialChunk.m_pNextAlloc = m_InitialChunk.m_pBase;
|
||||
m_pLastAllocedChunk = NULL;
|
||||
m_nFirstAvailableChunk = 0;
|
||||
int nCount = m_ExtraChunks.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
PhysicalChunk_t &chunk = m_ExtraChunks[i];
|
||||
MemAlloc_RegisterExternalDeallocation( CPhysicalMemoryStack, chunk.m_pBase, XPhysicalSize( chunk.m_pBase ) );
|
||||
XPhysicalFree( chunk.m_pBase );
|
||||
}
|
||||
m_ExtraChunks.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
void CPhysicalMemoryStack::PrintContents()
|
||||
{
|
||||
Msg( "Total used memory: %8d\n", GetUsed() );
|
||||
Msg( "Peak used memory: %8d\n", GetPeakUsed() );
|
||||
Msg( "Total allocated memory: %8d\n", GetSize() );
|
||||
}
|
||||
|
||||
|
||||
#endif // _X360
|
||||
38
tier1/miniprofiler_hash.cpp
Normal file
38
tier1/miniprofiler_hash.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
//========= Copyright (c) 2009, Valve Corporation, All rights reserved. ============//
|
||||
#include "tier0/platform.h"
|
||||
#include "tier1/miniprofiler_hash.h"
|
||||
|
||||
#if ENABLE_HARDWARE_PROFILER
|
||||
#include "tier1/UtlStringMap.h"
|
||||
CUtlStringMap<CLinkedMiniProfiler*> g_mapMiniProfilers;
|
||||
DLL_IMPORT CLinkedMiniProfiler *g_pOtherMiniProfilers;
|
||||
CLinkedMiniProfiler *HashMiniProfiler( const char *pString )
|
||||
{
|
||||
UtlSymId_t nString = g_mapMiniProfilers.Find( pString );
|
||||
if( nString == g_mapMiniProfilers.InvalidIndex() )
|
||||
{
|
||||
nString = g_mapMiniProfilers.AddString( pString );
|
||||
|
||||
// this profiler does not exist yet
|
||||
CLinkedMiniProfiler ** ppProfiler = &g_mapMiniProfilers[nString];
|
||||
*ppProfiler = new CLinkedMiniProfiler( g_mapMiniProfilers.String( nString ), &g_pOtherMiniProfilers );
|
||||
return *ppProfiler;
|
||||
}
|
||||
return g_mapMiniProfilers[nString];
|
||||
}
|
||||
CLinkedMiniProfiler *HashMiniProfilerF( const char *pFormat, ... )
|
||||
{
|
||||
va_list args;
|
||||
va_start( args, pFormat );
|
||||
char buffer[2048];
|
||||
Q_vsnprintf( buffer, sizeof( buffer ), pFormat, args );
|
||||
CLinkedMiniProfiler *pProfiler = HashMiniProfiler( buffer );
|
||||
va_end( args ) ;
|
||||
return pProfiler;
|
||||
}
|
||||
#else
|
||||
CMiniProfiler *HashMiniProfiler( const char *pString )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
1293
tier1/newbitbuf.cpp
Normal file
1293
tier1/newbitbuf.cpp
Normal file
File diff suppressed because it is too large
Load Diff
898
tier1/pathmatch.cpp
Normal file
898
tier1/pathmatch.cpp
Normal file
@@ -0,0 +1,898 @@
|
||||
//========= Copyright (c), Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Utility to interrogate and modify the data in the OSX IPC Server
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
// README:README
|
||||
//
|
||||
// This file implements the --wrap for ld on linux that lets file i/o api's
|
||||
// behave as if it were running on a case insensitive file system. Unfortunately,
|
||||
// this is needed by both steam2 and steam3. It was decided to check the source
|
||||
// into both locations, otherwise someone would find the .o and have no idea
|
||||
// where to go for the source if it was in the 'other' tree. Also, because this
|
||||
// needs to be linked into every elf binary, the .o is checked in for Steam3 so that it is
|
||||
// always available. In Steam2 it sits with the PosixWin32.cpp implementation and gets
|
||||
// compiled along side of it through the make system. If you are reading this in Steam3,
|
||||
// you will probably want to actually make your changes in steam2 and do a baseless merge
|
||||
// to the steam3 copy.
|
||||
//
|
||||
// HOWTO: Add a new function. Add the function with _WRAP to the makefiles as noted below.
|
||||
// Add the implementation to pathmatch.cpp - probably mimicking the existing functions.
|
||||
// Build steam2 and copy to matching steam3/client. Take the pathmatch.o from steam 2
|
||||
// and check it in to steam3 (in the location noted below). Full rebuild (re-link really)
|
||||
// of steam3. Test steam and check in.
|
||||
//
|
||||
// If you are looking at updating this file, please update the following as needed:
|
||||
//
|
||||
// STEAM2.../Projects/GazelleProto/Client/Engine/obj/RELEASE_NORMAL/libsteam_linux/Common/Misc/pathmatch.o
|
||||
// This is where steam2 builds the pathmatch.o out to.
|
||||
//
|
||||
// STEAM2.../Projects/GazelleProto/Makefile.shlib.base - contains _WRAP references
|
||||
// STEAM2.../Projects/Common/Misc/pathmatch.cpp - Where the source is checked in, keep in sync with:
|
||||
// STEAM3.../src/common/pathmatch.cpp - should be identical to previous file, but discoverable in steam3.
|
||||
// STEAM3.../src/lib/linux32/release/pathmatch.o - steam3 checked in version
|
||||
// STEAM3.../src/devtools/makefile_base_posix.mak - look for the _WRAP references
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/mount.h>
|
||||
#include <fcntl.h>
|
||||
#include <utime.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
// Enable to do pathmatch caching. Beware: this code isn't threadsafe.
|
||||
// #define DO_PATHMATCH_CACHE
|
||||
|
||||
#ifdef UTF8_PATHMATCH
|
||||
#define strcasecmp utf8casecmp
|
||||
#endif
|
||||
|
||||
static bool s_bShowDiag;
|
||||
#define DEBUG_MSG( ... ) if ( s_bShowDiag ) fprintf( stderr, ##__VA_ARGS__ )
|
||||
#define DEBUG_BREAK() __asm__ __volatile__ ( "int $3" )
|
||||
#define _COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}
|
||||
|
||||
#define WRAP( fn, ret, ... ) \
|
||||
ret __real_##fn(__VA_ARGS__); \
|
||||
ret __wrap_##fn(__VA_ARGS__)
|
||||
|
||||
#define CALL( fn ) __real_##fn
|
||||
|
||||
// Needed by pathmatch code
|
||||
extern "C" int __real_access(const char *pathname, int mode);
|
||||
extern "C" DIR *__real_opendir(const char *name);
|
||||
|
||||
|
||||
// UTF-8 work from PhysicsFS: http://icculus.org/physfs/
|
||||
// Even if it wasn't under the zlib license, Ryan wrote all this code originally.
|
||||
|
||||
#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF
|
||||
#define UNICODE_BOGUS_CHAR_CODEPOINT '?'
|
||||
|
||||
inline __attribute__ ((always_inline)) static uint32_t utf8codepoint(const char **_str)
|
||||
{
|
||||
const char *str = *_str;
|
||||
uint32_t retval = 0;
|
||||
uint32_t octet = (uint32_t) ((uint8_t) *str);
|
||||
uint32_t octet2, octet3, octet4;
|
||||
|
||||
if (octet == 0) // null terminator, end of string.
|
||||
return 0;
|
||||
|
||||
else if (octet < 128) // one octet char: 0 to 127
|
||||
{
|
||||
(*_str)++; // skip to next possible start of codepoint.
|
||||
return octet;
|
||||
}
|
||||
|
||||
else if ((octet > 127) && (octet < 192)) // bad (starts with 10xxxxxx).
|
||||
{
|
||||
// Apparently each of these is supposed to be flagged as a bogus
|
||||
// char, instead of just resyncing to the next valid codepoint.
|
||||
(*_str)++; // skip to next possible start of codepoint.
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
else if (octet < 224) // two octets
|
||||
{
|
||||
octet -= (128+64);
|
||||
octet2 = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet2 & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 2; // skip to next possible start of codepoint.
|
||||
retval = ((octet << 6) | (octet2 - 128));
|
||||
if ((retval >= 0x80) && (retval <= 0x7FF))
|
||||
return retval;
|
||||
}
|
||||
|
||||
else if (octet < 240) // three octets
|
||||
{
|
||||
octet -= (128+64+32);
|
||||
octet2 = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet2 & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet3 = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet3 & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 3; // skip to next possible start of codepoint.
|
||||
retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) );
|
||||
|
||||
// There are seven "UTF-16 surrogates" that are illegal in UTF-8.
|
||||
switch (retval)
|
||||
{
|
||||
case 0xD800:
|
||||
case 0xDB7F:
|
||||
case 0xDB80:
|
||||
case 0xDBFF:
|
||||
case 0xDC00:
|
||||
case 0xDF80:
|
||||
case 0xDFFF:
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
// 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge.
|
||||
if ((retval >= 0x800) && (retval <= 0xFFFD))
|
||||
return retval;
|
||||
}
|
||||
|
||||
else if (octet < 248) // four octets
|
||||
{
|
||||
octet -= (128+64+32+16);
|
||||
octet2 = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet2 & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet3 = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet3 & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet4 = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet4 & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 4; // skip to next possible start of codepoint.
|
||||
retval = ( ((octet << 18)) | ((octet2 - 128) << 12) |
|
||||
((octet3 - 128) << 6) | ((octet4 - 128)) );
|
||||
if ((retval >= 0x10000) && (retval <= 0x10FFFF))
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Five and six octet sequences became illegal in rfc3629.
|
||||
// We throw the codepoint away, but parse them to make sure we move
|
||||
// ahead the right number of bytes and don't overflow the buffer.
|
||||
|
||||
else if (octet < 252) // five octets
|
||||
{
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 5; // skip to next possible start of codepoint.
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
else // six octets
|
||||
{
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
octet = (uint32_t) ((uint8_t) *(++str));
|
||||
if ((octet & (128+64)) != 128) // Format isn't 10xxxxxx?
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
|
||||
*_str += 6; // skip to next possible start of codepoint.
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
return UNICODE_BOGUS_CHAR_VALUE;
|
||||
}
|
||||
|
||||
typedef struct CaseFoldMapping
|
||||
{
|
||||
uint32_t from;
|
||||
uint32_t to0;
|
||||
uint32_t to1;
|
||||
uint32_t to2;
|
||||
} CaseFoldMapping;
|
||||
|
||||
typedef struct CaseFoldHashBucket
|
||||
{
|
||||
const uint8_t count;
|
||||
const CaseFoldMapping *list;
|
||||
} CaseFoldHashBucket;
|
||||
|
||||
#include "pathmatch_casefolding.h"
|
||||
|
||||
inline __attribute__ ((always_inline)) static void locate_case_fold_mapping(const uint32_t from, uint32_t *to)
|
||||
{
|
||||
const uint8_t hashed = ((from ^ (from >> 8)) & 0xFF);
|
||||
const CaseFoldHashBucket *bucket = &case_fold_hash[hashed];
|
||||
const CaseFoldMapping *mapping = bucket->list;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < bucket->count; i++, mapping++)
|
||||
{
|
||||
if (mapping->from == from)
|
||||
{
|
||||
to[0] = mapping->to0;
|
||||
to[1] = mapping->to1;
|
||||
to[2] = mapping->to2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found...there's no remapping for this codepoint.
|
||||
to[0] = from;
|
||||
to[1] = 0;
|
||||
to[2] = 0;
|
||||
}
|
||||
|
||||
inline __attribute__ ((always_inline)) static uint32_t *fold_utf8(const char *str)
|
||||
{
|
||||
uint32_t *retval = new uint32_t[(strlen(str) * 3) + 1];
|
||||
uint32_t *dst = retval;
|
||||
while (*str)
|
||||
{
|
||||
const char ch = *str;
|
||||
if (ch & 0x80) // high bit set? UTF-8 sequence!
|
||||
{
|
||||
uint32_t fold[3];
|
||||
locate_case_fold_mapping(utf8codepoint(&str), fold);
|
||||
*(dst++) = fold[0];
|
||||
if (fold[1])
|
||||
{
|
||||
*(dst++) = fold[1];
|
||||
if (fold[2])
|
||||
*(dst++) = fold[2];
|
||||
}
|
||||
}
|
||||
else // simple ASCII test.
|
||||
{
|
||||
*(dst++) = (uint32_t) (((ch >= 'A') && (ch <= 'Z')) ? ch + 32 : ch);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
*dst = 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline __attribute__ ((always_inline)) static int utf8casecmp_loop(const uint32_t *folded1, const uint32_t *folded2)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const uint32_t ch1 = *(folded1++);
|
||||
const uint32_t ch2 = *(folded2++);
|
||||
if (ch1 < ch2)
|
||||
return -1;
|
||||
else if (ch1 > ch2)
|
||||
return 1;
|
||||
else if (ch1 == 0)
|
||||
return 0; // complete match.
|
||||
}
|
||||
}
|
||||
|
||||
static int utf8casecmp(const char *str1, const char *str2)
|
||||
{
|
||||
uint32_t *folded1 = fold_utf8(str1);
|
||||
uint32_t *folded2 = fold_utf8(str2);
|
||||
const int retval = utf8casecmp_loop(folded1, folded2);
|
||||
delete[] folded1;
|
||||
delete[] folded2;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Simple object to help make sure a DIR* from opendir
|
||||
// gets closed when it goes out of scope.
|
||||
class CDirPtr
|
||||
{
|
||||
public:
|
||||
CDirPtr() { m_pDir = NULL; }
|
||||
CDirPtr( DIR *pDir ) : m_pDir(pDir) {}
|
||||
~CDirPtr() { Close(); }
|
||||
|
||||
void operator=(DIR *pDir) { Close(); m_pDir = pDir; }
|
||||
|
||||
operator DIR *() { return m_pDir; }
|
||||
operator bool() { return m_pDir != NULL; }
|
||||
private:
|
||||
|
||||
void Close() { if ( m_pDir ) closedir( m_pDir ); }
|
||||
|
||||
DIR *m_pDir;
|
||||
};
|
||||
|
||||
// Object used to temporarily slice a path into a smaller componentent
|
||||
// and then repair it when going out of scope. Typically used as an unnamed
|
||||
// temp object that is a parameter to a function.
|
||||
class CDirTrimmer
|
||||
{
|
||||
public:
|
||||
CDirTrimmer( char * pPath, size_t nTrimIdx )
|
||||
{
|
||||
m_pPath = pPath;
|
||||
m_idx = nTrimIdx;
|
||||
m_c = m_pPath[nTrimIdx];
|
||||
m_pPath[nTrimIdx] = '\0';
|
||||
}
|
||||
~CDirTrimmer() { m_pPath[m_idx] = m_c; }
|
||||
|
||||
operator const char *() { return m_pPath; }
|
||||
|
||||
private:
|
||||
size_t m_idx;
|
||||
char *m_pPath;
|
||||
char m_c;
|
||||
};
|
||||
|
||||
|
||||
enum PathMod_t
|
||||
{
|
||||
kPathUnchanged,
|
||||
kPathLowered,
|
||||
kPathChanged,
|
||||
kPathFailed,
|
||||
};
|
||||
|
||||
static bool Descend( char *pPath, size_t nStartIdx, bool bAllowBasenameMismatch, size_t nLevel = 0 )
|
||||
{
|
||||
DEBUG_MSG( "(%zu) Descend: %s, (%s), %s\n", nLevel, pPath, pPath+nStartIdx, bAllowBasenameMismatch ? "true" : "false " );
|
||||
// We assume up through nStartIdx is valid and matching
|
||||
size_t nNextSlash = nStartIdx+1;
|
||||
|
||||
// path might be a dir
|
||||
if ( pPath[nNextSlash] == '\0' )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bIsDir = false; // is the new component a directory for certain?
|
||||
while ( pPath[nNextSlash] != '\0' && pPath[nNextSlash] != '/' )
|
||||
{
|
||||
nNextSlash++;
|
||||
}
|
||||
|
||||
// Modify the pPath string
|
||||
if ( pPath[nNextSlash] == '/' )
|
||||
bIsDir = true;
|
||||
|
||||
// See if we have an immediate match
|
||||
if ( __real_access( CDirTrimmer(pPath, nNextSlash), F_OK ) == 0 )
|
||||
{
|
||||
if ( !bIsDir )
|
||||
return true;
|
||||
|
||||
bool bRet = Descend( pPath, nNextSlash, bAllowBasenameMismatch, nLevel+1 );
|
||||
if ( bRet )
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start enumerating dirents
|
||||
CDirPtr spDir;
|
||||
if ( nStartIdx )
|
||||
{
|
||||
// we have a path
|
||||
spDir = __real_opendir( CDirTrimmer( pPath, nStartIdx ) );
|
||||
nStartIdx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we either start at root or cwd
|
||||
const char *pRoot = ".";
|
||||
if ( *pPath == '/' )
|
||||
{
|
||||
pRoot = "/";
|
||||
nStartIdx++;
|
||||
}
|
||||
spDir = __real_opendir( pRoot );
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
struct dirent *pEntry = spDir ? readdir( spDir ) : NULL;
|
||||
char *pszComponent = pPath + nStartIdx;
|
||||
size_t cbComponent = nNextSlash - nStartIdx;
|
||||
while ( pEntry )
|
||||
{
|
||||
DEBUG_MSG( "\t(%zu) comparing %s with %s\n", nLevel, pEntry->d_name, (const char *)CDirTrimmer(pszComponent, cbComponent) );
|
||||
|
||||
// the candidate must match the target, but not be a case-identical match (we would
|
||||
// have looked there in the short-circuit code above, so don't look again)
|
||||
bool bMatches = ( strcasecmp( CDirTrimmer(pszComponent, cbComponent), pEntry->d_name ) == 0 &&
|
||||
strcmp( CDirTrimmer(pszComponent, cbComponent), pEntry->d_name ) != 0 );
|
||||
|
||||
if ( bMatches )
|
||||
{
|
||||
char *pSrc = pEntry->d_name;
|
||||
char *pDst = &pPath[nStartIdx];
|
||||
// found a match; copy it in.
|
||||
while ( *pSrc && (*pSrc != '/') )
|
||||
{
|
||||
*pDst++ = *pSrc++;
|
||||
}
|
||||
|
||||
if ( !bIsDir )
|
||||
return true;
|
||||
|
||||
if ( Descend( pPath, nNextSlash, bAllowBasenameMismatch, nLevel+1 ) )
|
||||
return true;
|
||||
|
||||
// If descend fails, try more directories
|
||||
}
|
||||
pEntry = readdir( spDir );
|
||||
}
|
||||
|
||||
if ( bIsDir )
|
||||
{
|
||||
DEBUG_MSG( "(%zu) readdir failed to find '%s' in '%s'\n", nLevel, (const char *)CDirTrimmer(pszComponent, cbComponent), (const char *)CDirTrimmer( pPath, nStartIdx ) );
|
||||
}
|
||||
|
||||
// Sometimes it's ok for the filename portion to not match
|
||||
// since we might be opening for write. Note that if
|
||||
// the filename matches case insensitive, that will be
|
||||
// preferred over preserving the input name
|
||||
if ( !bIsDir && bAllowBasenameMismatch )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DO_PATHMATCH_CACHE
|
||||
typedef std::map<std::string, std::pair<std::string, time_t> > resultCache_t;
|
||||
typedef std::map<std::string, std::pair<std::string, time_t> >::iterator resultCacheItr_t;
|
||||
static resultCache_t resultCache;
|
||||
static const int k_cMaxCacheLifetimeSeconds = 2;
|
||||
#endif // DO_PATHMATCH_CACHE
|
||||
|
||||
PathMod_t pathmatch( const char *pszIn, char **ppszOut, bool bAllowBasenameMismatch, char *pszOutBuf, size_t OutBufLen )
|
||||
{
|
||||
static const char *s_pszDbgPathMatch = getenv("DBG_PATHMATCH");
|
||||
|
||||
s_bShowDiag = ( s_pszDbgPathMatch != NULL );
|
||||
|
||||
*ppszOut = NULL;
|
||||
|
||||
if ( __real_access( pszIn, F_OK ) == 0 )
|
||||
return kPathUnchanged;
|
||||
|
||||
#ifdef DO_PATHMATCH_CACHE
|
||||
resultCacheItr_t cachedResult = resultCache.find( pszIn );
|
||||
if ( cachedResult != resultCache.end() )
|
||||
{
|
||||
unsigned int age = time( NULL ) - cachedResult->second.second;
|
||||
const char *pszResult = cachedResult->second.first.c_str();
|
||||
if ( pszResult[0] != '\0' || age <= k_cMaxCacheLifetimeSeconds )
|
||||
{
|
||||
if ( pszResult[0] != '\0' )
|
||||
{
|
||||
*ppszOut = strdup( pszResult );
|
||||
DEBUG_MSG( "Cached '%s' -> '%s'\n", pszIn, *ppszOut );
|
||||
return kPathChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_MSG( "Cached '%s' -> kPathFailed\n", pszIn );
|
||||
return kPathFailed;
|
||||
}
|
||||
}
|
||||
else if ( age <= k_cMaxCacheLifetimeSeconds )
|
||||
{
|
||||
DEBUG_MSG( "Rechecking '%s' - cache is %u seconds old\n", pszIn, age );
|
||||
}
|
||||
}
|
||||
#endif // DO_PATHMATCH_CACHE
|
||||
|
||||
char *pPath;
|
||||
if( strlen( pszIn ) >= OutBufLen )
|
||||
{
|
||||
pPath = strdup( pszIn );
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy( pszOutBuf, pszIn, OutBufLen );
|
||||
pPath = pszOutBuf;
|
||||
}
|
||||
|
||||
if ( pPath )
|
||||
{
|
||||
// I believe this code is broken. I'm guessing someone wanted to avoid lowercasing
|
||||
// the path before the steam directory - but it's actually skipping lowercasing
|
||||
// whenever steam is found anywhere - including the filename. For example,
|
||||
// /home/mikesart/valvesrc/console/l4d2/game/left4dead2_dlc1/particles/steam_fx.pcf
|
||||
// winds up only having the "steam_fx.pcf" portion lowercased.
|
||||
#ifdef NEVER
|
||||
// optimization, if the path contained steam somewhere
|
||||
// assume the path up through the component with 'steam' in
|
||||
// is valid (because we almost certainly obtained it
|
||||
// progamatically
|
||||
char *p = strcasestr( pPath, "steam" );
|
||||
if ( p )
|
||||
{
|
||||
while ( p > pPath )
|
||||
{
|
||||
if ( p[-1] == '/' )
|
||||
break;
|
||||
p--;
|
||||
}
|
||||
|
||||
if ( ( p == pPath+1 ) && ( *pPath != '/' ) )
|
||||
p = pPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = pPath;
|
||||
}
|
||||
#else
|
||||
char *p = pPath;
|
||||
#endif
|
||||
|
||||
// Try the lower casing of the remaining path
|
||||
char *pBasename = p;
|
||||
while ( *p )
|
||||
{
|
||||
if ( *p == '/' )
|
||||
pBasename = p+1;
|
||||
|
||||
*p = tolower(*p);
|
||||
p++;
|
||||
}
|
||||
if ( __real_access( pPath, F_OK ) == 0 )
|
||||
{
|
||||
*ppszOut = pPath;
|
||||
DEBUG_MSG( "Lowered '%s' -> '%s'\n", pszIn, pPath );
|
||||
return kPathLowered;
|
||||
}
|
||||
|
||||
// path didn't match lowered successfully, restore the basename
|
||||
// if bAllowBasenameMismatch was true
|
||||
if ( bAllowBasenameMismatch )
|
||||
{
|
||||
const char *pSrc = pszIn + (pBasename - pPath);
|
||||
while ( *pBasename )
|
||||
{
|
||||
*pBasename++ = *pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( s_pszDbgPathMatch && strcasestr( s_pszDbgPathMatch, pszIn ) )
|
||||
{
|
||||
DEBUG_MSG( "Breaking '%s' in '%s'\n", pszIn, s_pszDbgPathMatch );
|
||||
DEBUG_BREAK();
|
||||
}
|
||||
|
||||
bool bSuccess = Descend( pPath, 0, bAllowBasenameMismatch );
|
||||
if ( bSuccess )
|
||||
{
|
||||
*ppszOut = pPath;
|
||||
DEBUG_MSG( "Matched '%s' -> '%s'\n", pszIn, pPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_MSG( "Unmatched %s\n", pszIn );
|
||||
}
|
||||
|
||||
#ifndef DO_PATHMATCH_CACHE
|
||||
return bSuccess ? kPathChanged : kPathFailed;
|
||||
#else
|
||||
time_t now = time(NULL);
|
||||
if ( bSuccess )
|
||||
{
|
||||
resultCache[ pszIn ] = std::make_pair( *ppszOut, now );
|
||||
return kPathChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultCache[ pszIn ] = std::make_pair( "", now );
|
||||
return kPathFailed;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return kPathFailed;
|
||||
}
|
||||
|
||||
// Wrapper object that manages the 'typical' usage cases of pathmatch()
|
||||
class CWrap
|
||||
{
|
||||
public:
|
||||
CWrap( const char *pSuppliedPath, bool bAllowMismatchedBasename )
|
||||
: m_pSuppliedPath( pSuppliedPath ), m_pBestMatch( NULL )
|
||||
{
|
||||
m_eResult = pathmatch( m_pSuppliedPath, &m_pBestMatch, bAllowMismatchedBasename, m_BestMatchBuf, sizeof( m_BestMatchBuf ) );
|
||||
if ( m_pBestMatch == NULL )
|
||||
{
|
||||
m_pBestMatch = const_cast<char*>( m_pSuppliedPath );
|
||||
}
|
||||
}
|
||||
|
||||
~CWrap()
|
||||
{
|
||||
if ( ( m_pBestMatch != m_pSuppliedPath ) && ( m_pBestMatch != m_BestMatchBuf ) )
|
||||
free( m_pBestMatch );
|
||||
}
|
||||
|
||||
const char *GetBest() const { return m_pBestMatch; }
|
||||
const char *GetOriginal() const { return m_pSuppliedPath; }
|
||||
PathMod_t GetMatchResult() const { return m_eResult; }
|
||||
|
||||
operator const char*() { return GetBest(); }
|
||||
|
||||
private:
|
||||
const char *m_pSuppliedPath;
|
||||
char *m_pBestMatch;
|
||||
char m_BestMatchBuf[ 512 ];
|
||||
PathMod_t m_eResult;
|
||||
};
|
||||
|
||||
#ifdef MAIN_TEST
|
||||
void usage()
|
||||
{
|
||||
puts("pathmatch [options] <path>");
|
||||
//puts("options:");
|
||||
//puts("\t");
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void test( const char *pszFile, bool bAllowBasenameMismatch )
|
||||
{
|
||||
char *pNewPath;
|
||||
char NewPathBuf[ 512 ];
|
||||
PathMod_t nStat = pathmatch( pszFile, &pNewPath, bAllowBasenameMismatch, NewPathBuf, sizeof( NewPathBuf ) );
|
||||
|
||||
printf("AllowMismatchedBasename: %s\n", bAllowBasenameMismatch ? "true" : "false" );
|
||||
printf("Path Was: ");
|
||||
switch ( nStat )
|
||||
{
|
||||
case kPathUnchanged:
|
||||
puts("kPathUnchanged");
|
||||
break;
|
||||
case kPathLowered:
|
||||
puts("kPathLowered");
|
||||
break;
|
||||
case kPathChanged:
|
||||
puts("kPathChanged");
|
||||
break;
|
||||
case kPathFailed:
|
||||
puts("kPathFailed");
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" Path In: %s\n", pszFile );
|
||||
printf("Path Out: %s\n", nStat == kPathUnchanged ? pszFile : pNewPath );
|
||||
|
||||
if ( pNewPath )
|
||||
free( pNewPath );
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if ( argc <= 1 || argc > 2 )
|
||||
usage();
|
||||
|
||||
test( argv[1], false );
|
||||
test( argv[1], true );
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
WRAP(freopen, FILE *, const char *path, const char *mode, FILE *stream)
|
||||
{
|
||||
// if mode does not have w, a, or +, it's open for read.
|
||||
bool bAllowBasenameMismatch = strpbrk( mode, "wa+" ) != NULL;
|
||||
CWrap mpath( path, bAllowBasenameMismatch );
|
||||
|
||||
return CALL(freopen)( mpath, mode, stream );
|
||||
}
|
||||
|
||||
WRAP(fopen, FILE *, const char *path, const char *mode)
|
||||
{
|
||||
// if mode does not have w, a, or +, it's open for read.
|
||||
bool bAllowBasenameMismatch = strpbrk( mode, "wa+" ) != NULL;
|
||||
CWrap mpath( path, bAllowBasenameMismatch );
|
||||
|
||||
return CALL(fopen)( mpath, mode );
|
||||
}
|
||||
|
||||
|
||||
WRAP(fopen64, FILE *, const char *path, const char *mode)
|
||||
{
|
||||
// if mode does not have w, a, or +, it's open for read.
|
||||
bool bAllowBasenameMismatch = strpbrk( mode, "wa+" ) != NULL;
|
||||
CWrap mpath( path, bAllowBasenameMismatch );
|
||||
|
||||
return CALL(fopen64)( mpath, mode );
|
||||
}
|
||||
|
||||
WRAP(open, int, const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
bool bAllowBasenameMismatch = ((flags & (O_WRONLY | O_RDWR)) != 0);
|
||||
CWrap mpath( pathname, bAllowBasenameMismatch );
|
||||
return CALL(open)( mpath, flags, mode );
|
||||
}
|
||||
|
||||
WRAP(open64, int, const char *pathname, int flags, mode_t mode)
|
||||
{
|
||||
bool bAllowBasenameMismatch = ((flags & (O_WRONLY | O_RDWR)) != 0);
|
||||
CWrap mpath( pathname, bAllowBasenameMismatch );
|
||||
return CALL(open64)( mpath, flags, mode );
|
||||
}
|
||||
|
||||
int __wrap_creat(const char *pathname, mode_t mode)
|
||||
{
|
||||
return __wrap_open( pathname, O_CREAT|O_WRONLY|O_TRUNC, mode );
|
||||
}
|
||||
|
||||
int __wrap_access(const char *pathname, int mode)
|
||||
{
|
||||
return __real_access( CWrap( pathname, false ), mode );
|
||||
}
|
||||
|
||||
WRAP(stat, int, const char *path, struct stat *buf)
|
||||
{
|
||||
return CALL(stat)( CWrap( path, false ), buf );
|
||||
}
|
||||
|
||||
WRAP(lstat, int, const char *path, struct stat *buf)
|
||||
{
|
||||
return CALL(lstat)( CWrap( path, false ), buf );
|
||||
}
|
||||
|
||||
WRAP(scandir, int, const char *dirp, struct dirent ***namelist,
|
||||
int (*filter)(const struct dirent *),
|
||||
int (*compar)(const struct dirent **, const struct dirent **))
|
||||
{
|
||||
return CALL(scandir)( CWrap( dirp, false ), namelist, filter, compar );
|
||||
}
|
||||
|
||||
WRAP(opendir, DIR*, const char *name)
|
||||
{
|
||||
return CALL(opendir)( CWrap( name, false ) );
|
||||
}
|
||||
|
||||
WRAP(__xstat, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__xstat)( __ver, CWrap( __filename, false), __stat_buf );
|
||||
}
|
||||
|
||||
WRAP(__lxstat, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__lxstat)( __ver, CWrap( __filename, false), __stat_buf );
|
||||
}
|
||||
|
||||
WRAP(__xstat64, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__xstat64)( __ver, CWrap( __filename, false), __stat_buf );
|
||||
}
|
||||
|
||||
WRAP(__lxstat64, int, int __ver, __const char *__filename, struct stat *__stat_buf)
|
||||
{
|
||||
return CALL(__lxstat64)( __ver, CWrap( __filename, false), __stat_buf );
|
||||
}
|
||||
|
||||
WRAP(chmod, int, const char *path, mode_t mode)
|
||||
{
|
||||
return CALL(chmod)( CWrap( path, false), mode );
|
||||
}
|
||||
|
||||
WRAP(chown, int, const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
return CALL(chown)( CWrap( path, false), owner, group );
|
||||
}
|
||||
|
||||
WRAP(lchown, int, const char *path, uid_t owner, gid_t group)
|
||||
{
|
||||
return CALL(lchown)( CWrap( path, false), owner, group );
|
||||
}
|
||||
|
||||
WRAP(symlink, int, const char *oldpath, const char *newpath)
|
||||
{
|
||||
return CALL(symlink)( CWrap( oldpath, false), CWrap( newpath, true ) );
|
||||
}
|
||||
|
||||
WRAP(link, int, const char *oldpath, const char *newpath)
|
||||
{
|
||||
return CALL(link)( CWrap( oldpath, false), CWrap( newpath, true ) );
|
||||
}
|
||||
|
||||
WRAP(mknod, int, const char *pathname, mode_t mode, dev_t dev)
|
||||
{
|
||||
return CALL(mknod)( CWrap( pathname, true), mode, dev );
|
||||
}
|
||||
|
||||
WRAP(mount, int, const char *source, const char *target,
|
||||
const char *filesystemtype, unsigned long mountflags,
|
||||
const void *data)
|
||||
{
|
||||
return CALL(mount)( CWrap( source, false ), CWrap( target, false ), filesystemtype, mountflags, data );
|
||||
}
|
||||
|
||||
WRAP(unlink, int, const char *pathname)
|
||||
{
|
||||
return CALL(unlink)( CWrap( pathname, false ) );
|
||||
}
|
||||
|
||||
WRAP(mkfifo, int, const char *pathname, mode_t mode)
|
||||
{
|
||||
return CALL(mkfifo)( CWrap( pathname, true ), mode );
|
||||
}
|
||||
|
||||
WRAP(rename, int, const char *oldpath, const char *newpath)
|
||||
{
|
||||
return CALL(rename)( CWrap( oldpath, false), CWrap( newpath, true ) );
|
||||
}
|
||||
|
||||
WRAP(utime, int, const char *filename, const struct utimbuf *times)
|
||||
{
|
||||
return CALL(utime)( CWrap( filename, false), times );
|
||||
}
|
||||
|
||||
WRAP(utimes, int, const char *filename, const struct timeval times[2])
|
||||
{
|
||||
return CALL(utimes)( CWrap( filename, false), times );
|
||||
}
|
||||
|
||||
WRAP(realpath, char *, const char *path, char *resolved_path)
|
||||
{
|
||||
return CALL(realpath)( CWrap( path, true ), resolved_path );
|
||||
}
|
||||
|
||||
WRAP(mkdir, int, const char *pathname, mode_t mode)
|
||||
{
|
||||
return CALL(mkdir)( CWrap( pathname, true ), mode );
|
||||
}
|
||||
|
||||
WRAP(rmdir, char *, const char *pathname)
|
||||
{
|
||||
return CALL(rmdir)( CWrap( pathname, false ) );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
2007
tier1/pathmatch_casefolding.h
Normal file
2007
tier1/pathmatch_casefolding.h
Normal file
File diff suppressed because it is too large
Load Diff
290
tier1/processor_detect.cpp
Normal file
290
tier1/processor_detect.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: win32 dependant ASM code for CPU capability detection
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#if defined( POSIX )
|
||||
#else // POSIX
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
#if defined( _X360 )
|
||||
|
||||
bool CheckMMXTechnology(void) { return false; }
|
||||
bool CheckSSETechnology(void) { return false; }
|
||||
bool CheckSSE2Technology(void) { return false; }
|
||||
bool Check3DNowTechnology(void) { return false; }
|
||||
|
||||
#elif defined( _M_X64 )
|
||||
|
||||
bool CheckMMXTechnology(void) { return true; }
|
||||
bool CheckSSETechnology(void) { return true; }
|
||||
bool CheckSSE2Technology(void) { return true; }
|
||||
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
|
||||
|
||||
#endif // POSIX
|
||||
80
tier1/processor_detect_linux.cpp
Normal file
80
tier1/processor_detect_linux.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: linux dependant ASM code for CPU capability detection
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
// NOTE: This has to be the last file included! (turned off below, since this is included like a header)
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// Turn off memdbg macros (turned on up top) since this is included like a header
|
||||
#include "tier0/memdbgoff.h"
|
||||
|
||||
static void cpuid(uint32 function, uint32& out_eax, uint32& out_ebx, uint32& out_ecx, uint32& out_edx)
|
||||
{
|
||||
#if defined(PLATFORM_64BITS)
|
||||
asm("mov %%rbx, %%rsi\n\t"
|
||||
"cpuid\n\t"
|
||||
"xchg %%rsi, %%rbx"
|
||||
: "=a" (out_eax),
|
||||
"=S" (out_ebx),
|
||||
"=c" (out_ecx),
|
||||
"=d" (out_edx)
|
||||
: "a" (function)
|
||||
);
|
||||
#else
|
||||
asm("mov %%ebx, %%esi\n\t"
|
||||
"cpuid\n\t"
|
||||
"xchg %%esi, %%ebx"
|
||||
: "=a" (out_eax),
|
||||
"=S" (out_ebx),
|
||||
"=c" (out_ecx),
|
||||
"=d" (out_edx)
|
||||
: "a" (function)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CheckMMXTechnology(void)
|
||||
{
|
||||
uint32 eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x800000;
|
||||
}
|
||||
|
||||
bool CheckSSETechnology(void)
|
||||
{
|
||||
uint32 eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x2000000L;
|
||||
}
|
||||
|
||||
bool CheckSSE2Technology(void)
|
||||
{
|
||||
uint32 eax,ebx,edx,unused;
|
||||
cpuid(1,eax,ebx,unused,edx);
|
||||
|
||||
return edx & 0x04000000;
|
||||
}
|
||||
|
||||
bool Check3DNowTechnology(void)
|
||||
{
|
||||
uint32 eax, unused;
|
||||
cpuid(0x80000000,eax,unused,unused,unused);
|
||||
|
||||
if ( eax > 0x80000000L )
|
||||
{
|
||||
cpuid(0x80000001,unused,unused,unused,eax);
|
||||
return ( eax & 1<<31 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
111
tier1/qsort_s.cpp
Normal file
111
tier1/qsort_s.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/******************************************************************/
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
41
tier1/rangecheckedvar.cpp
Normal file
41
tier1/rangecheckedvar.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
//========= Copyright © 1996-2005, 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
141
tier1/sparsematrix.cpp
Normal file
141
tier1/sparsematrix.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
//===== Copyright © 1996-2006, 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
102
tier1/splitstring.cpp
Normal file
102
tier1/splitstring.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
#include "strtools.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
CSplitString::CSplitString()
|
||||
{
|
||||
m_szBuffer = nullptr;
|
||||
}
|
||||
|
||||
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::Set(const char *pString, const char **pSeparators, int nSeparators)
|
||||
{
|
||||
delete[] m_szBuffer;
|
||||
Construct(pString, pSeparators, nSeparators);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
126
tier1/stringpool.cpp
Normal file
126
tier1/stringpool.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
//===== Copyright © 1996-2005, 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 StrLessInsensitive( const char * const &pszLeft, const char * const &pszRight )
|
||||
{
|
||||
return ( Q_stricmp( pszLeft, pszRight) < 0 );
|
||||
}
|
||||
|
||||
bool StrLessSensitive( const char * const &pszLeft, const char * const &pszRight )
|
||||
{
|
||||
return ( Q_strcmp( pszLeft, pszRight) < 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CStringPool::CStringPool( StringPoolCase_t caseSensitivity )
|
||||
: m_Strings( 32, 256, caseSensitivity == StringPoolCaseInsensitive ? StrLessInsensitive : StrLessSensitive )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
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 );
|
||||
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();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#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
|
||||
5118
tier1/strtools.cpp
Normal file
5118
tier1/strtools.cpp
Normal file
File diff suppressed because it is too large
Load Diff
561
tier1/strtools_unicode.cpp
Normal file
561
tier1/strtools_unicode.cpp
Normal file
@@ -0,0 +1,561 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: determine if a uchar32 represents a valid Unicode code point
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Q_IsValidUChar32( uchar32 uVal )
|
||||
{
|
||||
// Values > 0x10FFFF are explicitly invalid; ditto for UTF-16 surrogate halves,
|
||||
// values ending in FFFE or FFFF, or values in the 0x00FDD0-0x00FDEF reserved range
|
||||
return ( uVal < 0x110000u ) && ( (uVal - 0x00D800u) > 0x7FFu ) && ( (uVal & 0xFFFFu) < 0xFFFEu ) && ( ( uVal - 0x00FDD0u ) > 0x1Fu );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return number of UTF-8 bytes required to encode a Unicode code point
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UChar32ToUTF8Len( uchar32 uVal )
|
||||
{
|
||||
DbgAssert( Q_IsValidUChar32( uVal ) );
|
||||
if ( uVal <= 0x7F )
|
||||
return 1;
|
||||
if ( uVal <= 0x7FF )
|
||||
return 2;
|
||||
if ( uVal <= 0xFFFF )
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return number of UTF-16 elements required to encode a Unicode code point
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UChar32ToUTF16Len( uchar32 uVal )
|
||||
{
|
||||
DbgAssert( Q_IsValidUChar32( uVal ) );
|
||||
if ( uVal <= 0xFFFF )
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: encode Unicode code point as UTF-8, returns number of bytes written
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UChar32ToUTF8( uchar32 uVal, char *pUTF8Out )
|
||||
{
|
||||
DbgAssert( Q_IsValidUChar32( uVal ) );
|
||||
if ( uVal <= 0x7F )
|
||||
{
|
||||
pUTF8Out[0] = (unsigned char) uVal;
|
||||
return 1;
|
||||
}
|
||||
if ( uVal <= 0x7FF )
|
||||
{
|
||||
pUTF8Out[0] = (unsigned char)(uVal >> 6) | 0xC0;
|
||||
pUTF8Out[1] = (unsigned char)(uVal & 0x3F) | 0x80;
|
||||
return 2;
|
||||
}
|
||||
if ( uVal <= 0xFFFF )
|
||||
{
|
||||
pUTF8Out[0] = (unsigned char)(uVal >> 12) | 0xE0;
|
||||
pUTF8Out[1] = (unsigned char)((uVal >> 6) & 0x3F) | 0x80;
|
||||
pUTF8Out[2] = (unsigned char)(uVal & 0x3F) | 0x80;
|
||||
return 3;
|
||||
}
|
||||
pUTF8Out[0] = (unsigned char)((uVal >> 18) & 0x07) | 0xF0;
|
||||
pUTF8Out[1] = (unsigned char)((uVal >> 12) & 0x3F) | 0x80;
|
||||
pUTF8Out[2] = (unsigned char)((uVal >> 6) & 0x3F) | 0x80;
|
||||
pUTF8Out[3] = (unsigned char)(uVal & 0x3F) | 0x80;
|
||||
return 4;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: encode Unicode code point as UTF-16, returns number of elements written
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UChar32ToUTF16( uchar32 uVal, uchar16 *pUTF16Out )
|
||||
{
|
||||
DbgAssert( Q_IsValidUChar32( uVal ) );
|
||||
if ( uVal <= 0xFFFF )
|
||||
{
|
||||
pUTF16Out[0] = (uchar16) uVal;
|
||||
return 1;
|
||||
}
|
||||
uVal -= 0x010000;
|
||||
pUTF16Out[0] = (uchar16)(uVal >> 10) | 0xD800;
|
||||
pUTF16Out[1] = (uchar16)(uVal & 0x3FF) | 0xDC00;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
// Decode one character from a UTF-8 encoded string. Treats 6-byte CESU-8 sequences
|
||||
// as a single character, as if they were a correctly-encoded 4-byte UTF-8 sequence.
|
||||
int Q_UTF8ToUChar32( const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut )
|
||||
{
|
||||
const uint8 *pUTF8 = (const uint8 *)pUTF8_;
|
||||
|
||||
int nBytes = 1;
|
||||
uint32 uValue = pUTF8[0];
|
||||
uint32 uMinValue = 0;
|
||||
|
||||
// 0....... single byte
|
||||
if ( uValue < 0x80 )
|
||||
goto decodeFinishedNoCheck;
|
||||
|
||||
// Expecting at least a two-byte sequence with 0xC0 <= first <= 0xF7 (110...... and 11110...)
|
||||
if ( (uValue - 0xC0u) > 0x37u || ( pUTF8[1] & 0xC0 ) != 0x80 )
|
||||
goto decodeError;
|
||||
|
||||
uValue = (uValue << 6) - (0xC0 << 6) + pUTF8[1] - 0x80;
|
||||
nBytes = 2;
|
||||
uMinValue = 0x80;
|
||||
|
||||
// 110..... two-byte lead byte
|
||||
if ( !( uValue & (0x20 << 6) ) )
|
||||
goto decodeFinished;
|
||||
|
||||
// Expecting at least a three-byte sequence
|
||||
if ( ( pUTF8[2] & 0xC0 ) != 0x80 )
|
||||
goto decodeError;
|
||||
|
||||
uValue = (uValue << 6) - (0x20 << 12) + pUTF8[2] - 0x80;
|
||||
nBytes = 3;
|
||||
uMinValue = 0x800;
|
||||
|
||||
// 1110.... three-byte lead byte
|
||||
if ( !( uValue & (0x10 << 12) ) )
|
||||
goto decodeFinishedMaybeCESU8;
|
||||
|
||||
// Expecting a four-byte sequence, longest permissible in UTF-8
|
||||
if ( ( pUTF8[3] & 0xC0 ) != 0x80 )
|
||||
goto decodeError;
|
||||
|
||||
uValue = (uValue << 6) - (0x10 << 18) + pUTF8[3] - 0x80;
|
||||
nBytes = 4;
|
||||
uMinValue = 0x10000;
|
||||
|
||||
// 11110... four-byte lead byte. fall through to finished.
|
||||
|
||||
decodeFinished:
|
||||
if ( uValue >= uMinValue && Q_IsValidUChar32( uValue ) )
|
||||
{
|
||||
decodeFinishedNoCheck:
|
||||
uValueOut = uValue;
|
||||
bErrorOut = false;
|
||||
return nBytes;
|
||||
}
|
||||
decodeError:
|
||||
uValueOut = '?';
|
||||
bErrorOut = true;
|
||||
return nBytes;
|
||||
|
||||
decodeFinishedMaybeCESU8:
|
||||
// Do we have a full UTF-16 surrogate pair that's been UTF-8 encoded afterwards?
|
||||
// That is, do we have 0xD800-0xDBFF followed by 0xDC00-0xDFFF? If so, decode it all.
|
||||
if ( ( uValue - 0xD800u ) < 0x400u && pUTF8[3] == 0xED && (uint8)( pUTF8[4] - 0xB0 ) < 0x10 && ( pUTF8[5] & 0xC0 ) == 0x80 )
|
||||
{
|
||||
uValue = 0x10000 + ( ( uValue - 0xD800u ) << 10 ) + ( (uint8)( pUTF8[4] - 0xB0 ) << 6 ) + pUTF8[5] - 0x80;
|
||||
nBytes = 6;
|
||||
uMinValue = 0x10000;
|
||||
}
|
||||
goto decodeFinished;
|
||||
}
|
||||
|
||||
// Decode one character from a UTF-16 encoded string.
|
||||
int Q_UTF16ToUChar32( const uchar16 *pUTF16, uchar32 &uValueOut, bool &bErrorOut )
|
||||
{
|
||||
if ( Q_IsValidUChar32( pUTF16[0] ) )
|
||||
{
|
||||
uValueOut = pUTF16[0];
|
||||
bErrorOut = false;
|
||||
return 1;
|
||||
}
|
||||
else if ( (pUTF16[0] - 0xD800u) < 0x400u && (pUTF16[1] - 0xDC00u) < 0x400u )
|
||||
{
|
||||
// Valid surrogate pair, but maybe not encoding a valid Unicode code point...
|
||||
uchar32 uVal = 0x010000 + ((pUTF16[0] - 0xD800u) << 10) + (pUTF16[1] - 0xDC00);
|
||||
if ( Q_IsValidUChar32( uVal ) )
|
||||
{
|
||||
uValueOut = uVal;
|
||||
bErrorOut = false;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
uValueOut = '?';
|
||||
bErrorOut = true;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uValueOut = '?';
|
||||
bErrorOut = true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
namespace // internal use only
|
||||
{
|
||||
// Identity transformations and validity tests for use with Q_UnicodeConvertT
|
||||
int Q_UTF32ToUChar32( const uchar32 *pUTF32, uchar32 &uVal, bool &bErr )
|
||||
{
|
||||
bErr = !Q_IsValidUChar32( *pUTF32 );
|
||||
uVal = bErr ? '?' : *pUTF32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Q_UChar32ToUTF32Len( uchar32 uVal )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Q_UChar32ToUTF32( uchar32 uVal, uchar32 *pUTF32 )
|
||||
{
|
||||
*pUTF32 = uVal;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// A generic Unicode processing loop: decode one character from input to uchar32, handle errors, encode uchar32 to output
|
||||
template < typename SrcType, typename DstType, bool bStopAtNull, int (&DecodeSrc)( const SrcType*, uchar32&, bool& ), int (&EncodeDstLen)( uchar32 ), int (&EncodeDst)( uchar32, DstType* ) >
|
||||
int Q_UnicodeConvertT( const SrcType *pIn, int nInChars, DstType *pOut, int nOutBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
int nOut = 0;
|
||||
|
||||
if ( !pOut )
|
||||
{
|
||||
while ( bStopAtNull ? ( *pIn ) : ( nInChars-- > 0 ) )
|
||||
{
|
||||
uchar32 uVal;
|
||||
// Initialize in order to avoid /analyze warnings.
|
||||
bool bErr = false;
|
||||
pIn += DecodeSrc( pIn, uVal, bErr );
|
||||
nOut += EncodeDstLen( uVal );
|
||||
if ( bErr )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
AssertMsg( !(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence" );
|
||||
#endif
|
||||
if ( ePolicy & _STRINGCONVERTFLAG_SKIP )
|
||||
{
|
||||
nOut -= EncodeDstLen( uVal );
|
||||
}
|
||||
else if ( ePolicy & _STRINGCONVERTFLAG_FAIL )
|
||||
{
|
||||
pOut[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nOutElems = nOutBytes / sizeof( DstType );
|
||||
if ( nOutElems <= 0 )
|
||||
return 0;
|
||||
|
||||
int nMaxOut = nOutElems - 1;
|
||||
while ( bStopAtNull ? ( *pIn ) : ( nInChars-- > 0 ) )
|
||||
{
|
||||
uchar32 uVal;
|
||||
// Initialize in order to avoid /analyze warnings.
|
||||
bool bErr = false;
|
||||
pIn += DecodeSrc( pIn, uVal, bErr );
|
||||
if ( nOut + EncodeDstLen( uVal ) > nMaxOut )
|
||||
break;
|
||||
nOut += EncodeDst( uVal, pOut + nOut );
|
||||
if ( bErr )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
AssertMsg( !(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence" );
|
||||
#endif
|
||||
if ( ePolicy & _STRINGCONVERTFLAG_SKIP )
|
||||
{
|
||||
nOut -= EncodeDstLen( uVal );
|
||||
}
|
||||
else if ( ePolicy & _STRINGCONVERTFLAG_FAIL )
|
||||
{
|
||||
pOut[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
pOut[nOut] = 0;
|
||||
}
|
||||
|
||||
return (nOut + 1) * sizeof( DstType );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if UTF-8 string contains invalid sequences.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Q_UnicodeValidate( const char *pUTF8 )
|
||||
{
|
||||
bool bError = false;
|
||||
while ( *pUTF8 )
|
||||
{
|
||||
uchar32 uVal;
|
||||
// Our UTF-8 decoder silently fixes up 6-byte CESU-8 (improperly re-encoded UTF-16) sequences.
|
||||
// However, these are technically not valid UTF-8. So if we eat 6 bytes at once, it's an error.
|
||||
int nCharSize = Q_UTF8ToUChar32( pUTF8, uVal, bError );
|
||||
if ( bError || nCharSize == 6 )
|
||||
return false;
|
||||
pUTF8 += nCharSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if UTF-16 string contains invalid sequences.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Q_UnicodeValidate( const uchar16 *pUTF16 )
|
||||
{
|
||||
bool bError = false;
|
||||
while ( *pUTF16 )
|
||||
{
|
||||
uchar32 uVal;
|
||||
pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError );
|
||||
if ( bError )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if UTF-32 string contains invalid sequences.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Q_UnicodeValidate( const uchar32 *pUTF32 )
|
||||
{
|
||||
while ( *pUTF32 )
|
||||
{
|
||||
if ( !Q_IsValidUChar32( *pUTF32++ ) )
|
||||
return false;
|
||||
++pUTF32;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-8 string
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UnicodeLength( const char *pUTF8 )
|
||||
{
|
||||
int nChars = 0;
|
||||
while ( *pUTF8 )
|
||||
{
|
||||
bool bError;
|
||||
uchar32 uVal;
|
||||
pUTF8 += Q_UTF8ToUChar32( pUTF8, uVal, bError );
|
||||
++nChars;
|
||||
}
|
||||
return nChars;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-16 string
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UnicodeLength( const uchar16 *pUTF16 )
|
||||
{
|
||||
int nChars = 0;
|
||||
while ( *pUTF16 )
|
||||
{
|
||||
bool bError;
|
||||
uchar32 uVal;
|
||||
pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError );
|
||||
++nChars;
|
||||
}
|
||||
return nChars;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-32 string
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UnicodeLength( const uchar32 *pUTF32 )
|
||||
{
|
||||
int nChars = 0;
|
||||
while ( *pUTF32++ )
|
||||
++nChars;
|
||||
return nChars;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Advance a UTF-8 string pointer by a certain number of Unicode code points, stopping at end of string
|
||||
//-----------------------------------------------------------------------------
|
||||
char *Q_UnicodeAdvance( char *pUTF8, int nChars )
|
||||
{
|
||||
while ( nChars > 0 && *pUTF8 )
|
||||
{
|
||||
uchar32 uVal;
|
||||
bool bError;
|
||||
pUTF8 += Q_UTF8ToUChar32( pUTF8, uVal, bError );
|
||||
--nChars;
|
||||
}
|
||||
return pUTF8;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Advance a UTF-16 string pointer by a certain number of Unicode code points, stopping at end of string
|
||||
//-----------------------------------------------------------------------------
|
||||
uchar16 *Q_UnicodeAdvance( uchar16 *pUTF16, int nChars )
|
||||
{
|
||||
while ( nChars > 0 && *pUTF16 )
|
||||
{
|
||||
uchar32 uVal;
|
||||
bool bError;
|
||||
pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError );
|
||||
--nChars;
|
||||
}
|
||||
return pUTF16;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Advance a UTF-32 string pointer by a certain number of Unicode code points, stopping at end of string
|
||||
//-----------------------------------------------------------------------------
|
||||
uchar32 *Q_UnicodeAdvance( uchar32 *pUTF32, int nChars )
|
||||
{
|
||||
while ( nChars > 0 && *pUTF32 )
|
||||
{
|
||||
++pUTF32;
|
||||
--nChars;
|
||||
}
|
||||
return pUTF32;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF8ToUTF16( const char *pUTF8, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< char, uchar16, true, Q_UTF8ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF8, 0, pUTF16, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF8ToUTF32( const char *pUTF8, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< char, uchar32, true, Q_UTF8ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF8, 0, pUTF32, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF16ToUTF8( const uchar16 *pUTF16, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar16, char, true, Q_UTF16ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF16, 0, pUTF8, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF16ToUTF32( const uchar16 *pUTF16, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar16, uchar32, true, Q_UTF16ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF16, 0, pUTF32, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF32ToUTF8( const uchar32 *pUTF32, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar32, char, true, Q_UTF32ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF32, 0, pUTF8, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF32ToUTF16( const uchar32 *pUTF32, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar32, uchar16, true, Q_UTF32ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF32, 0, pUTF16, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF32ToUTF32( const uchar32 *pUTF32Source, uchar32 *pUTF32Dest, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar32, uchar32, true, Q_UTF32ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF32Source, 0, pUTF32Dest, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF8CharsToUTF16( const char *pUTF8, int nElements, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< char, uchar16, false, Q_UTF8ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF8, nElements, pUTF16, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF8CharsToUTF32( const char *pUTF8, int nElements, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< char, uchar32, false, Q_UTF8ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF8, nElements, pUTF32, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF16CharsToUTF8( const uchar16 *pUTF16, int nElements, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar16, char, false, Q_UTF16ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF16, nElements, pUTF8, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF16CharsToUTF32( const uchar16 *pUTF16, int nElements, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar16, uchar32, false, Q_UTF16ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF16, nElements, pUTF32, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF32CharsToUTF8( const uchar32 *pUTF32, int nElements, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar32, char, false, Q_UTF32ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF32, nElements, pUTF8, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UTF32CharsToUTF16( const uchar32 *pUTF32, int nElements, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar32, uchar16, false, Q_UTF32ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF32, nElements, pUTF16, cubDestSizeInBytes, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Repair a UTF-8 string by removing or replacing invalid seqeuences. Returns non-zero on success.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UnicodeRepair( char *pUTF8, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< char, char, true, Q_UTF8ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF8, 0, pUTF8, INT_MAX, ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Repair a UTF-16 string by removing or replacing invalid seqeuences. Returns non-zero on success.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UnicodeRepair( uchar16 *pUTF16, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar16, uchar16, true, Q_UTF16ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF16, 0, pUTF16, INT_MAX/sizeof(uchar16), ePolicy );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Repair a UTF-32 string by removing or replacing invalid seqeuences. Returns non-zero on success.
|
||||
//-----------------------------------------------------------------------------
|
||||
int Q_UnicodeRepair( uchar32 *pUTF32, EStringConvertErrorPolicy ePolicy )
|
||||
{
|
||||
return Q_UnicodeConvertT< uchar32, uchar32, true, Q_UTF32ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF32, 0, pUTF32, INT_MAX/sizeof(uchar32), ePolicy );
|
||||
}
|
||||
|
||||
29
tier1/tier1.cpp
Normal file
29
tier1/tier1.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
//===== Copyright © 2005-2005, 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 "interfaces/interfaces.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 )
|
||||
{
|
||||
ConnectInterfaces( pFactoryList, nFactoryCount );
|
||||
}
|
||||
|
||||
void DisconnectTier1Libraries()
|
||||
{
|
||||
DisconnectInterfaces();
|
||||
}
|
||||
163
tier1/tier1.vpc
Normal file
163
tier1/tier1.vpc
Normal file
@@ -0,0 +1,163 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 "appinstance.cpp"
|
||||
$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 "circularbuffer.cpp"
|
||||
$File "commandbuffer.cpp"
|
||||
$File "convar.cpp"
|
||||
$File "datamanager.cpp"
|
||||
$File "diff.cpp"
|
||||
$File "exprevaluator.cpp"
|
||||
$File "generichash.cpp"
|
||||
$File "interface.cpp"
|
||||
$File "keyvalues.cpp"
|
||||
$File "keyvaluesjson.cpp"
|
||||
$File "kvpacker.cpp"
|
||||
$File "lzmaDecoder.cpp"
|
||||
$File "lzss.cpp"
|
||||
$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 "stringpool.cpp"
|
||||
$File "strtools.cpp"
|
||||
$File "strtools_unicode.cpp"
|
||||
$File "tier1.cpp"
|
||||
$File "tier1_logging.cpp"
|
||||
$File "timeutils.cpp"
|
||||
$File "uniqueid.cpp"
|
||||
$File "utlbuffer.cpp"
|
||||
$File "utlbufferutil.cpp"
|
||||
$File "utlsoacontainer.cpp"
|
||||
$File "utlstring.cpp"
|
||||
$File "utlstringtoken.cpp"
|
||||
$File "utlsymbol.cpp"
|
||||
$File "miniprofiler_hash.cpp"
|
||||
$File "sparsematrix.cpp"
|
||||
$File "memoverride_dummy.cpp"
|
||||
|
||||
$File "../tier1/pathmatch.cpp" [$LINUXALL]
|
||||
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\tier1\appinstance.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\circularbuffer.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\exprevaluator.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\interface.h"
|
||||
$File "$SRCDIR\public\tier1\interpolatedvar.h"
|
||||
$File "$SRCDIR\public\tier1\keyvalues.h"
|
||||
$File "$SRCDIR\public\tier1\keyvaluesjson.h"
|
||||
$File "$SRCDIR\public\tier1\kvpacker.h"
|
||||
$File "$SRCDIR\public\tier1\lzmaDecoder.h"
|
||||
$File "$SRCDIR\public\tier1\lerp_functions.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\sparsematrix.h"
|
||||
$File "$SRCDIR\public\tier1\stringpool.h"
|
||||
$File "$SRCDIR\public\tier1\strtools.h"
|
||||
$File "$SRCDIR\public\tier1\tier1.h"
|
||||
$File "$SRCDIR\public\tier1\tier1_logging.h"
|
||||
$File "$SRCDIR\public\tier1\timeutils.h"
|
||||
$File "$SRCDIR\public\tier1\tokenset.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\utlsoacontainer.h"
|
||||
$File "$SRCDIR\public\tier1\utlsortvector.h"
|
||||
$File "$SRCDIR\public\tier1\utlstack.h"
|
||||
$File "$SRCDIR\public\tier1\utlstring.h"
|
||||
$File "$SRCDIR\public\tier1\utlstringtoken.h"
|
||||
$File "$SRCDIR\public\tier1\utlstringmap.h"
|
||||
$File "$SRCDIR\public\tier1\utlsymbol.h"
|
||||
$File "$SRCDIR\public\tier1\utltscache.h"
|
||||
$File "$SRCDIR\public\tier1\utlvector.h"
|
||||
$File "$SRCDIR\public\tier1\miniprofiler_hash.h"
|
||||
$File "$SRCDIR\common\xbox\xboxstubs.h" [$WINDOWS||$POSIX]
|
||||
}
|
||||
}
|
||||
13
tier1/tier1.vpc.vpc_cache
Normal file
13
tier1/tier1.vpc.vpc_cache
Normal file
@@ -0,0 +1,13 @@
|
||||
"vpc_cache"
|
||||
{
|
||||
"CacheVersion" "1"
|
||||
"win32"
|
||||
{
|
||||
"CRCFile" "tier1.vcxproj.vpc_crc"
|
||||
"OutputFiles"
|
||||
{
|
||||
"0" "tier1.vcxproj"
|
||||
"1" "tier1.vcxproj.filters"
|
||||
}
|
||||
}
|
||||
}
|
||||
14
tier1/tier1_exclude.vpc
Normal file
14
tier1/tier1_exclude.vpc
Normal file
@@ -0,0 +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]
|
||||
}
|
||||
}
|
||||
48
tier1/tier1_logging.cpp
Normal file
48
tier1/tier1_logging.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
||||
//
|
||||
// Tier1 logging helpers.
|
||||
//
|
||||
//===============================================================================
|
||||
|
||||
#include "tier1_logging.h"
|
||||
|
||||
CBufferedLoggingListener::CBufferedLoggingListener() :
|
||||
m_StoredSpew( 0, 512, 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void CBufferedLoggingListener::Log( const LoggingContext_t *pContext, const tchar *pMessage )
|
||||
{
|
||||
m_StoredSpew.PutInt( pContext->m_ChannelID );
|
||||
m_StoredSpew.PutInt( pContext->m_Severity );
|
||||
m_StoredSpew.PutChar( pContext->m_Color.r() );
|
||||
m_StoredSpew.PutChar( pContext->m_Color.g() );
|
||||
m_StoredSpew.PutChar( pContext->m_Color.b() );
|
||||
m_StoredSpew.PutChar( pContext->m_Color.a() );
|
||||
m_StoredSpew.PutString( pMessage );
|
||||
}
|
||||
|
||||
void CBufferedLoggingListener::EmitBufferedSpew()
|
||||
{
|
||||
while ( m_StoredSpew.GetBytesRemaining() > 0 )
|
||||
{
|
||||
LoggingChannelID_t channelID = m_StoredSpew.GetInt();
|
||||
LoggingSeverity_t severity = ( LoggingSeverity_t )m_StoredSpew.GetInt();
|
||||
unsigned char r, g, b, a;
|
||||
r = m_StoredSpew.GetChar();
|
||||
g = m_StoredSpew.GetChar();
|
||||
b = m_StoredSpew.GetChar();
|
||||
a = m_StoredSpew.GetChar();
|
||||
Color color( r, g, b, a );
|
||||
|
||||
int nLen = m_StoredSpew.PeekStringLength();
|
||||
if ( nLen )
|
||||
{
|
||||
char *pMessage = ( char * )stackalloc( nLen );
|
||||
m_StoredSpew.GetString( pMessage, nLen );
|
||||
LoggingSystem_LogDirect( channelID, severity, color, pMessage );
|
||||
}
|
||||
}
|
||||
|
||||
m_StoredSpew.Clear();
|
||||
}
|
||||
525
tier1/tier1unittests_ps3.cpp
Normal file
525
tier1/tier1unittests_ps3.cpp
Normal file
@@ -0,0 +1,525 @@
|
||||
#include "unitlib/unitlib.h"
|
||||
#include "tier1/commandbuffer.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
|
||||
#if defined( UNIT_TESTS_ENABLED ) && defined( _PS3 )
|
||||
extern "C" bool _tier1_unit_tests(void)
|
||||
{
|
||||
for( int i = 0; i < UnitTestCount(); i++ )
|
||||
{
|
||||
ITestCase* pThisTest = GetUnitTest( i );
|
||||
Assert( pThisTest );
|
||||
if( pThisTest )
|
||||
pThisTest->RunTest();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_TESTSUITE( CommandBufferTestSuite )
|
||||
|
||||
DEFINE_TESTCASE( CommandBufferTestSimple, CommandBufferTestSuite )
|
||||
{
|
||||
Msg( "Simple command buffer test...\n" );
|
||||
|
||||
CCommandBuffer buffer;
|
||||
buffer.AddText( "test_command test_arg1 test_arg2" );
|
||||
buffer.AddText( "test_command2 test_arg3; test_command3 test_arg4" );
|
||||
buffer.AddText( "test_command4\ntest_command5" );
|
||||
buffer.AddText( "test_command6 // Comment; test_command7" );
|
||||
buffer.AddText( "test_command8 // Comment; test_command9\ntest_command10" );
|
||||
buffer.AddText( "test_command11 \"test_arg5 test_arg6\"" );
|
||||
buffer.AddText( "test_command12 \"\"" );
|
||||
buffer.AddText( "// Comment\ntest_command13\t\t\"test_arg7\"" );
|
||||
buffer.AddText( "test_command14\"test_arg8\"test_arg9" );
|
||||
buffer.AddText( "test_command15 test_arg10" );
|
||||
buffer.AddText( "test_command16 test_arg11:test_arg12" );
|
||||
|
||||
CCommand command;
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 3 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg1" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg2" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "test_arg1 test_arg2" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 2 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command2" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg3" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "test_arg3" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 2 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command3" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg4" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "test_arg4" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command4" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command5" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command6" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command8" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command10" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 2 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command11" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg5 test_arg6" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "\"test_arg5 test_arg6\"" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 2 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command12" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "\"\"" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 2 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command13" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg7" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "\"test_arg7\"" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 3 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command14" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg8" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg9" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "\"test_arg8\"test_arg9" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 2 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command15" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg10" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "test_arg10" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 4 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command16" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg11" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], ":" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[3], "test_arg12" ) );
|
||||
Shipping_Assert( !Q_stricmp( command.ArgS(), "test_arg11:test_arg12" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
|
||||
|
||||
DEFINE_TESTCASE( CommandBufferTestTiming, CommandBufferTestSuite )
|
||||
{
|
||||
Msg( "Delayed command buffer test...\n" );
|
||||
|
||||
CCommandBuffer buffer;
|
||||
|
||||
buffer.AddText( "test_command test_arg1 test_arg2" );
|
||||
buffer.AddText( "test_command2 test_arg1 test_arg2 test_arg3", kCommandSrcUserInput, 1 );
|
||||
buffer.AddText( "test_command3;wait;test_command4;wait 2;test_command5" );
|
||||
|
||||
CCommand command;
|
||||
{
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 3 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg1" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg2" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command3" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
{
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 4 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command2" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg1" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg2" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[3], "test_arg3" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command4" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
{
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
{
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command5" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEFINE_TESTCASE( CommandBufferTestNested, CommandBufferTestSuite )
|
||||
{
|
||||
Msg( "Nested command buffer test...\n" );
|
||||
|
||||
CCommandBuffer buffer;
|
||||
buffer.AddText( "test_command test_arg1 test_arg2" );
|
||||
buffer.AddText( "test_command2 test_arg3 test_arg4 test_arg5", 2 );
|
||||
|
||||
CCommand command;
|
||||
{
|
||||
buffer.BeginProcessingCommands( 2 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 3 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg1" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg2" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.AddText( "test_command3;test_command4", 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command3" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command4" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
{
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 4 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command2" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg3" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg4" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[3], "test_arg5" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEFINE_TESTCASE( CommandBufferTestOverflow, CommandBufferTestSuite )
|
||||
{
|
||||
Msg( "Command buffer overflow test...\n" );
|
||||
|
||||
CCommandBuffer buffer;
|
||||
|
||||
buffer.LimitArgumentBufferSize( 40 );
|
||||
bool bOk = buffer.AddText( "test_command test_arg1 test_arg2" ); // 32 chars
|
||||
Shipping_Assert( bOk );
|
||||
bOk = buffer.AddText( "test_command2 test_arg3 test_arg4 test_arg5", 2 ); // 43 chars
|
||||
Shipping_Assert( !bOk );
|
||||
|
||||
CCommand command;
|
||||
{
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 3 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg1" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg2" ) );
|
||||
|
||||
bOk = buffer.AddText( "test_command3 test_arg6;wait;test_command4" );
|
||||
Shipping_Assert( bOk );
|
||||
|
||||
// This makes sure that AddText doesn't cause argv to become bogus after
|
||||
// compacting memory
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg1" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[2], "test_arg2" ) );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 2 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command3" ) );
|
||||
Shipping_Assert( !Q_stricmp( command[1], "test_arg6" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
{
|
||||
buffer.BeginProcessingCommands( 1 );
|
||||
|
||||
Verify( buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 1 );
|
||||
Shipping_Assert( !Q_stricmp( command[0], "test_command4" ) );
|
||||
|
||||
Verify( !buffer.DequeueNextCommand( &command ) );
|
||||
Shipping_Assert( command.ArgC() == 0 );
|
||||
|
||||
buffer.EndProcessingCommands( );
|
||||
}
|
||||
}
|
||||
|
||||
template < class A >
|
||||
bool TestValueAndGutters( A atest[3], const A &a, const char *mtest )
|
||||
{
|
||||
bool bSuccess0 = V_memcmp( &atest[ 0 ], mtest, sizeof( atest[ 0 ] ) ) == 0;
|
||||
bool bSuccess1 = atest[ 1 ] == a;
|
||||
bool bSuccess2 = V_memcmp( &atest[ 2 ], mtest, sizeof( atest[ 2 ] ) ) == 0;
|
||||
Shipping_Assert( bSuccess0 && bSuccess1 && bSuccess2 );
|
||||
return bSuccess0 && bSuccess1 && bSuccess2;
|
||||
}
|
||||
|
||||
bool TestString( CUtlBuffer &buf, const char *pString )
|
||||
{
|
||||
char strtest[ 1023 ];
|
||||
int nLen = buf.GetUpTo( strtest, sizeof( strtest ) );
|
||||
strtest[ nLen ] = '\0';
|
||||
|
||||
bool bSuccessStr = V_strcmp( pString, strtest ) == 0;
|
||||
Shipping_Assert( bSuccessStr );
|
||||
return bSuccessStr;
|
||||
}
|
||||
|
||||
template < class A >
|
||||
void TestScanfAndPrintf( const char *pString, const A &a )
|
||||
{
|
||||
char mtest[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"; // 0x555555...
|
||||
A atest[3]; V_memset( atest, mtest[0], sizeof( atest ) );
|
||||
|
||||
|
||||
CUtlBuffer strbuf( pString, V_strlen( pString ) + 1, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
|
||||
|
||||
const char *pScanFmt = GetFmtStr<A>();
|
||||
strbuf.Scanf( pScanFmt, &atest[1] );
|
||||
|
||||
bool bSuccessA = TestValueAndGutters( atest, a, mtest );
|
||||
if ( !bSuccessA )
|
||||
{
|
||||
Msg( "CUtlBuffer::Scanf '%s' FAILED!\n", pString );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CUtlBuffer valbuf( 0, 1024, CUtlBuffer::TEXT_BUFFER );
|
||||
const char *pPrintFmt = GetFmtStr<A>();
|
||||
valbuf.Printf( pPrintFmt, atest[1] ); // we know that a == atest[1] from before
|
||||
|
||||
if ( !TestString( valbuf, pString ) )
|
||||
{
|
||||
Msg( "CUtlBuffer::Printf '%s' FAILED!\n", pString );
|
||||
}
|
||||
}
|
||||
|
||||
template < class A, class B >
|
||||
void TestScanfAndPrintf( const char *pString, const A &a, const B &b )
|
||||
{
|
||||
char mtest[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"; // 0x555555...
|
||||
A atest[3]; V_memset( atest, mtest[0], sizeof( atest ) );
|
||||
B btest[3]; V_memset( btest, mtest[0], sizeof( btest ) );
|
||||
|
||||
|
||||
CUtlBuffer strbuf( pString, V_strlen( pString ) + 1, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
|
||||
|
||||
char scanfmt[ 256 ];
|
||||
V_snprintf( scanfmt, sizeof( scanfmt ), "%s %s", GetFmtStr<A>( 10, false ), GetFmtStr<B>( 10, false ) );
|
||||
strbuf.Scanf( scanfmt, &atest[1], &btest[1] );
|
||||
|
||||
bool bSuccessA = TestValueAndGutters( atest, a, mtest );
|
||||
bool bSuccessB = TestValueAndGutters( btest, b, mtest );
|
||||
if ( !bSuccessA || !bSuccessB )
|
||||
{
|
||||
Msg( "CUtlBuffer::Scanf '%s' FAILED!\n", pString );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CUtlBuffer valbuf( 0, 1024, CUtlBuffer::TEXT_BUFFER );
|
||||
char printfmt[ 256 ];
|
||||
V_snprintf( printfmt, sizeof( printfmt ), "%s %s", GetFmtStr<A>(), GetFmtStr<B>() );
|
||||
valbuf.Printf( printfmt, atest[1], btest[1] ); // we know that a == atest[1] and b == btest[1] from before
|
||||
|
||||
if ( !TestString( valbuf, pString ) )
|
||||
{
|
||||
Msg( "CUtlBuffer::Printf '%s' FAILED!\n", pString );
|
||||
}
|
||||
}
|
||||
|
||||
template < class A, class B, class C >
|
||||
void TestScanfAndPrintf( const char *pString, const A &a, const B &b, const C &c )
|
||||
{
|
||||
const char mtest[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"; // 0x555555...
|
||||
A atest[3]; V_memset( atest, mtest[0], sizeof( atest ) );
|
||||
B btest[3]; V_memset( btest, mtest[0], sizeof( btest ) );
|
||||
C ctest[3]; V_memset( ctest, mtest[0], sizeof( ctest ) );
|
||||
|
||||
|
||||
CUtlBuffer strbuf( pString, V_strlen( pString ) + 1, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
|
||||
|
||||
char scanfmt[ 256 ];
|
||||
V_snprintf( scanfmt, sizeof( scanfmt ), "%s %s %s", GetFmtStr<A>( 10, false ), GetFmtStr<B>( 10, false ), GetFmtStr<C>( 10, false ) );
|
||||
strbuf.Scanf( scanfmt, &atest[1], &btest[1], &ctest[1] );
|
||||
|
||||
bool bSuccessA = TestValueAndGutters( atest, a, mtest );
|
||||
bool bSuccessB = TestValueAndGutters( btest, b, mtest );
|
||||
bool bSuccessC = TestValueAndGutters( ctest, c, mtest );
|
||||
if ( !bSuccessA || !bSuccessB || !bSuccessC )
|
||||
{
|
||||
Msg( "CUtlBuffer::Scanf '%s' FAILED!\n", pString );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CUtlBuffer valbuf( 0, 1024, CUtlBuffer::TEXT_BUFFER );
|
||||
char printfmt[ 256 ];
|
||||
V_snprintf( printfmt, sizeof( printfmt ), "%s %s %s", GetFmtStr<A>(), GetFmtStr<B>(), GetFmtStr<C>() );
|
||||
valbuf.Printf( printfmt, atest[1], btest[1], ctest[1] ); // we know that a == atest[1] and b == btest[1] and c == ctest[1] from before
|
||||
|
||||
if ( !TestString( valbuf, pString ) )
|
||||
{
|
||||
Msg( "CUtlBuffer::Printf '%s' FAILED!\n", pString );
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
void TestGetPut( T ( CUtlBuffer::*getfunc )(), void ( CUtlBuffer::*putfunc )( T ), const char *pString, const T &value )
|
||||
{
|
||||
{
|
||||
CUtlBuffer valbuf( 0, 1024, CUtlBuffer::TEXT_BUFFER );
|
||||
|
||||
char mtest[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"; // 0x555555...
|
||||
T valtest[3];
|
||||
V_memset( valtest, mtest[0], sizeof( valtest ) );
|
||||
valtest[1] = value;
|
||||
|
||||
( valbuf.*putfunc )( valtest[1] );
|
||||
|
||||
if ( !TestValueAndGutters( valtest, value, mtest ) )
|
||||
{
|
||||
Msg( "CUtlBuffer::PutXXX FAILED!\n" );
|
||||
}
|
||||
|
||||
if ( !TestString( valbuf, pString ) )
|
||||
{
|
||||
Msg( "CUtlBuffer::PutXXX FAILED!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
CUtlBuffer strbuf( pString, V_strlen( pString ) + 1, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
|
||||
|
||||
char mtest[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"; // 0x555555...
|
||||
T valtest[3];
|
||||
V_memset( valtest, mtest[0], sizeof( valtest ) );
|
||||
|
||||
valtest[1] = (strbuf.*getfunc)();
|
||||
|
||||
if ( !TestValueAndGutters( valtest, value, mtest ) )
|
||||
{
|
||||
Msg( "CUtlBuffer::GetXXX FAILED!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
// {
|
||||
// CUtlBuffer strbuf( pString, V_strlen( pString ) + 1, CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
|
||||
//
|
||||
// char mtest[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"; // 0x555555...
|
||||
// T valtest[3];
|
||||
// V_memset( valtest, mtest[0], sizeof( valtest ) );
|
||||
//
|
||||
// char fmt[ 256 ];
|
||||
// V_snprintf( fmt, sizeof( fmt ), "%s", GetFmtStr<T>() );
|
||||
//
|
||||
// strbuf.GetType( valtest[1], fmt );
|
||||
//
|
||||
// if ( !TestValueAndGutters( valtest, value, mtest ) )
|
||||
// {
|
||||
// Msg( "CUtlBuffer::GetType FAILED!\n" );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
DEFINE_TESTSUITE( UtlBufferTestSuite )
|
||||
|
||||
|
||||
DEFINE_TESTCASE( UtlBufferTestScanf, UtlBufferTestSuite )
|
||||
{
|
||||
Msg( "CUtlBuffer::Scanf test...\n" );
|
||||
|
||||
TestScanfAndPrintf( "-1234567890 12345 0.123456789012345", -1234567890, 12345u, 0.123456789012345 );
|
||||
TestScanfAndPrintf( "-12345 0.123456", -12345, 0.123456f );
|
||||
TestScanfAndPrintf( "1234567890", 1234567890u );
|
||||
TestScanfAndPrintf( "1234567890123456789", 1234567890123456789ll );
|
||||
}
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
DEFINE_TESTCASE( UtlBufferTestGetPut, UtlBufferTestSuite )
|
||||
{
|
||||
Msg( "CUtlBuffer Get/Put test...\n" );
|
||||
|
||||
// TestGetPut< char >( &CUtlBuffer::GetChar, &CUtlBuffer::PutChar, "-123", -123i8 ); // GetChar()/PutChar() always read/write a single byte, even in text mode
|
||||
TestGetPut< uchar >( &CUtlBuffer::GetUnsignedChar, &CUtlBuffer::PutUnsignedChar, "123", 123 );
|
||||
TestGetPut< short >( &CUtlBuffer::GetShort, &CUtlBuffer::PutShort, "-12345", -12345 );
|
||||
TestGetPut< ushort >( &CUtlBuffer::GetUnsignedShort, &CUtlBuffer::PutUnsignedShort, "12345", 12345u );
|
||||
TestGetPut< int >( &CUtlBuffer::GetInt, &CUtlBuffer::PutInt, "-1234567890", -1234567890 );
|
||||
TestGetPut< uint >( &CUtlBuffer::GetUnsignedInt, &CUtlBuffer::PutUnsignedInt, "1234567890", 1234567890u );
|
||||
// TestGetPut< int >( &CUtlBuffer::GetIntHex, &CUtlBuffer::PutIntHex, "123", 123i8 ); // there is no PutIntHex()
|
||||
TestGetPut< int64 >( &CUtlBuffer::GetInt64, &CUtlBuffer::PutInt64, "1234567890123456789", 1234567890123456789ll );
|
||||
TestGetPut< float >( &CUtlBuffer::GetFloat, &CUtlBuffer::PutFloat, "0.123456", 0.123456f );
|
||||
TestGetPut< double >( &CUtlBuffer::GetDouble, &CUtlBuffer::PutDouble, "0.123456789012345", 0.123456789012345 );
|
||||
}
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
405
tier1/timeutils.cpp
Normal file
405
tier1/timeutils.cpp
Normal file
@@ -0,0 +1,405 @@
|
||||
|
||||
#include "tier1/timeutils.h"
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/utlbufferutil.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DmeFramerate_t
|
||||
//
|
||||
// exact (rational) representation of common framerates - any integral or ntsc framerate
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DmeFramerate_t::DmeFramerate_t( float fps )
|
||||
{
|
||||
SetFramerate( fps );
|
||||
}
|
||||
|
||||
DmeFramerate_t::DmeFramerate_t( int fps /*= 0*/ ) :
|
||||
m_num( fps ), m_den( 10000 )
|
||||
{
|
||||
}
|
||||
|
||||
DmeFramerate_t::DmeFramerate_t( int nNumerator, int nDenominator ) :
|
||||
m_num( nNumerator ), m_den( nDenominator * 10000 )
|
||||
{
|
||||
}
|
||||
|
||||
void DmeFramerate_t::SetFramerate( float flFrameRate )
|
||||
{
|
||||
if ( IsIntegralValue( flFrameRate ) )
|
||||
{
|
||||
SetFramerate( RoundFloatToInt( flFrameRate ) );
|
||||
}
|
||||
else if ( IsIntegralValue( flFrameRate * 1001.0f / 1000.0f, 0.01f ) ) // 1001 is the ntsc divisor (30*1000/1001 = 29.97, etc)
|
||||
{
|
||||
SetFramerateNTSC( RoundFloatToInt( flFrameRate * 1001.0f / 1000.0f ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( 0 );
|
||||
SetFramerate( RoundFloatToInt( flFrameRate ) );
|
||||
}
|
||||
}
|
||||
|
||||
void DmeFramerate_t::SetFramerate( int fps )
|
||||
{
|
||||
m_num = fps;
|
||||
m_den = 10000;
|
||||
}
|
||||
|
||||
// other (uncommon) options besides 30(29.97 - ntsc video) are 24 (23.976 - ntsc film) and 60 (59.94 - ntsc progressive)
|
||||
void DmeFramerate_t::SetFramerateNTSC( int multiplier /*= 30*/ )
|
||||
{
|
||||
// ntsc = 30 fps * 1000 / 1001
|
||||
// = ( 30 / 10000 fptms ) * 1000 / 1001
|
||||
// = 30 / 10010
|
||||
m_num = multiplier;
|
||||
m_den = 10010;
|
||||
}
|
||||
|
||||
float DmeFramerate_t::GetFramesPerSecond() const
|
||||
{
|
||||
return 10000.0f * m_num / float( m_den );
|
||||
}
|
||||
|
||||
DmeTime_t DmeFramerate_t::GetTimePerFrame() const
|
||||
{
|
||||
return DmeTime_t( m_den / m_num );
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DmeTime_t
|
||||
//
|
||||
// representing time as integral tenths of a millisecond (tms)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DmeTime_t::DmeTime_t( int frame, DmeFramerate_t framerate )
|
||||
{
|
||||
int64 num = int64( framerate.m_num );
|
||||
int64 prod = frame * int64( framerate.m_den );
|
||||
// add signed offset to force integer truncation (towards 0) to give us truncation towards -inf
|
||||
if ( frame < 0 )
|
||||
{
|
||||
prod -= num - 1;
|
||||
}
|
||||
m_tms = int( prod / num ); // round tms towards 0
|
||||
}
|
||||
|
||||
|
||||
// float operators - comment these out to find potentially incorrect uses of DmeTime_t
|
||||
|
||||
DmeTime_t DmeTime_t::operator*=( float f )
|
||||
{
|
||||
m_tms = int( floor( m_tms * f + 0.5f ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
DmeTime_t DmeTime_t::operator/=( float f )
|
||||
{
|
||||
m_tms = int( floor( m_tms / f + 0.5f ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// helper methods
|
||||
|
||||
void DmeTime_t::Clamp( DmeTime_t lo, DmeTime_t hi )
|
||||
{
|
||||
m_tms = clamp( m_tms, lo.m_tms, hi.m_tms );
|
||||
}
|
||||
|
||||
bool DmeTime_t::IsInRange( DmeTime_t lo, DmeTime_t hi ) const
|
||||
{
|
||||
return m_tms >= lo.m_tms && m_tms < hi.m_tms;
|
||||
}
|
||||
|
||||
|
||||
// helper functions
|
||||
|
||||
float GetFractionOfTimeBetween( DmeTime_t t, DmeTime_t start, DmeTime_t end, bool bClamp /*= false*/ )
|
||||
{
|
||||
return GetFractionOfTime( t - start, end - start, bClamp );
|
||||
}
|
||||
|
||||
float GetFractionOfTime( DmeTime_t t, DmeTime_t duration, bool bClamp /*= false*/ )
|
||||
{
|
||||
if ( duration == DMETIME_ZERO )
|
||||
return 0.0f;
|
||||
|
||||
if ( bClamp )
|
||||
{
|
||||
t.Clamp( DMETIME_ZERO, duration );
|
||||
}
|
||||
return t.m_tms / float( duration.m_tms );
|
||||
}
|
||||
|
||||
int FrameForTime( DmeTime_t t, DmeFramerate_t framerate )
|
||||
{
|
||||
return t.CurrentFrame( framerate );
|
||||
}
|
||||
|
||||
|
||||
// framerate-dependent conversions to/from frames
|
||||
|
||||
int DmeTime_t::CurrentFrame( DmeFramerate_t framerate, RoundStyle_t roundStyle /*=ROUND_DOWN*/ ) const
|
||||
{
|
||||
int64 den = int64( framerate.m_den );
|
||||
int64 num = int64( framerate.m_num );
|
||||
int64 prod = int64( m_tms ) * num;
|
||||
|
||||
// times within this range are considered on a frame: (frame*den/num - 1, frame*den/num]
|
||||
// this follows from the truncation towards -inf behavior of the frame,framerate constructor above
|
||||
// the following logic is there to ensure the above rule,
|
||||
// while working around the truncation towards 0 behavior of integer divide
|
||||
|
||||
if ( m_tms < 0 )
|
||||
{
|
||||
if ( roundStyle == ROUND_NEAREST )
|
||||
return int( ( prod - den/2 + num ) / den );
|
||||
if ( roundStyle == ROUND_DOWN )
|
||||
return int( ( prod - den + num ) / den );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( roundStyle == ROUND_NEAREST )
|
||||
return int( ( prod + den/2 ) / den ); // this is intentionally not symmetric with the negative case, s.t. nearest always rounds up at half-frames (rather than always towards 0)
|
||||
if ( roundStyle == ROUND_UP )
|
||||
return int( ( prod + den - num ) / den );
|
||||
if ( roundStyle == ROUND_DOWN )
|
||||
return int( ( prod + num ) / den );
|
||||
}
|
||||
|
||||
return int( prod / den );
|
||||
}
|
||||
|
||||
DmeTime_t DmeTime_t::TimeAtCurrentFrame( DmeFramerate_t framerate, RoundStyle_t roundStyle /*=ROUND_DOWN*/ ) const
|
||||
{
|
||||
int frame = CurrentFrame( framerate, roundStyle );
|
||||
return DmeTime_t( frame, framerate );
|
||||
}
|
||||
DmeTime_t DmeTime_t::TimeAtNextFrame( DmeFramerate_t framerate ) const
|
||||
{
|
||||
// since we always round towards -inf, go to next frame whether we're on a frame or not
|
||||
int frame = CurrentFrame( framerate, ROUND_DOWN );
|
||||
return DmeTime_t( frame + 1, framerate );
|
||||
}
|
||||
DmeTime_t DmeTime_t::TimeAtPrevFrame( DmeFramerate_t framerate ) const
|
||||
{
|
||||
int frame = CurrentFrame( framerate, ROUND_UP );
|
||||
return DmeTime_t( frame - 1, framerate ); // we're exactly on a frame
|
||||
}
|
||||
|
||||
|
||||
int DmeTime_t::RoundSecondsToTMS( float sec )
|
||||
{
|
||||
return (int)floor( 10000.0f * sec + 0.5f ); // round at half-tms boundary
|
||||
}
|
||||
|
||||
int DmeTime_t::RoundSecondsToTMS( double sec )
|
||||
{
|
||||
return (int)floor( 10000.0 * sec + 0.5 ); // round at half-tms boundary
|
||||
}
|
||||
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const DmeTime_t &src )
|
||||
{
|
||||
int tms = src.GetTenthsOfMS();
|
||||
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
#if 1
|
||||
double tms = src.GetTenthsOfMS();
|
||||
buf.Printf( "%.04f", tms / 10000 );
|
||||
#else
|
||||
int tms = src.GetTenthsOfMS();
|
||||
uint postms = tms; // can't just negate tms, since -INT_MIN == INT_MIN
|
||||
if ( tms < 0 )
|
||||
{
|
||||
buf.PutChar( '-' );
|
||||
postms = -tms;
|
||||
}
|
||||
int seconds = postms / 10000;
|
||||
int remainder = postms % 10000;
|
||||
buf.Printf( "%d.%04d", seconds, remainder );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutInt( tms );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, DmeTime_t &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
buf.EatWhiteSpace();
|
||||
#if 1
|
||||
double tms = buf.GetDouble() * 10000;
|
||||
if ( !buf.IsValid() )
|
||||
return false;
|
||||
|
||||
if ( tms < INT_MIN || tms > INT_MAX )
|
||||
return false;
|
||||
|
||||
dest.SetTenthsOfMS( ( int )floor( tms + 0.5 ) );
|
||||
#else
|
||||
char str[ 16 ];
|
||||
buf.GetString( str, sizeof( str ) );
|
||||
if ( !buf.IsValid() )
|
||||
return false;
|
||||
|
||||
char *p = str;
|
||||
|
||||
bool bNegative = *p == '-';
|
||||
if ( bNegative )
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
bool bSeenDigit = false;
|
||||
bool bOverflow = false;
|
||||
int seconds = 0;
|
||||
while ( isdigit( *p ) )
|
||||
{
|
||||
seconds = seconds * 10 + *p++ - '0';
|
||||
bSeenDigit = true;
|
||||
bOverflow = seconds > INT_MAX / 10000; // once this goes invalid, it stays that way, so no extra check is needed
|
||||
}
|
||||
|
||||
int remainder = 0;
|
||||
if ( *p == '.' )
|
||||
{
|
||||
++p;
|
||||
|
||||
int multiplier = 1000;
|
||||
while ( isdigit( *p ) )
|
||||
{
|
||||
remainder += multiplier * ( *p++ - '0' );
|
||||
multiplier /= 10;
|
||||
bSeenDigit = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint tms = seconds * 10000 + remainder;
|
||||
if ( bOverflow || !bSeenDigit || ( tms > ( bNegative ? ( uint )-INT_MIN : INT_MAX ) ) )
|
||||
return false;
|
||||
|
||||
dest.SetTenthsOfMS( bNegative ? -tms : tms );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int tms = buf.GetInt();
|
||||
if ( !buf.IsValid() )
|
||||
return false;
|
||||
|
||||
dest.SetTenthsOfMS( tms );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DmeTime_t serialization/unserialization tests
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0 // not as necessary now that CUtlBuffer::GetDouble() works
|
||||
|
||||
class CTestTimeSerialization
|
||||
{
|
||||
public:
|
||||
|
||||
CTestTimeSerialization()
|
||||
{
|
||||
TestSerialization( DMETIME_INVALID );
|
||||
TestSerialization( DMETIME_MINTIME );
|
||||
TestSerialization( DMETIME_MAXTIME );
|
||||
TestSerialization( DMETIME_MINDELTA );
|
||||
TestSerialization( DMETIME_ZERO );
|
||||
TestSerialization( "214748.3647" );
|
||||
TestSerialization( "214748.3648", NULL, false );
|
||||
TestSerialization( "500000.0000", NULL, false );
|
||||
TestSerialization( "-214748.3648" );
|
||||
TestSerialization( "-214748.3649", NULL, false );
|
||||
TestSerialization( "-500000.0000", NULL, false );
|
||||
TestSerialization( "1.2", "1.2000" );
|
||||
TestSerialization( "1", "1.0000" );
|
||||
TestSerialization( "1.", "1.0000" );
|
||||
TestSerialization( ".2", "0.2000" );
|
||||
TestSerialization( "-1.2", "-1.2000" );
|
||||
TestSerialization( "-1.", "-1.0000" );
|
||||
TestSerialization( "-1", "-1.0000" );
|
||||
TestSerialization( "-.2", "-0.2000" );
|
||||
TestSerialization( "1.23456", "1.2345" );
|
||||
TestSerialization( "-1.23456", "-1.2345" );
|
||||
}
|
||||
|
||||
void TestSerialization( DmeTime_t time )
|
||||
{
|
||||
CUtlBuffer buf( 0, 20, CUtlBuffer::TEXT_BUFFER );
|
||||
Serialize( buf, time );
|
||||
|
||||
DmeTime_t test;
|
||||
if ( !Unserialize( buf, test ) )
|
||||
{
|
||||
Msg( "TestUnserialize: %d failed\n", time.GetTenthsOfMS() );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( time != test )
|
||||
{
|
||||
Msg( "TestUnserialize: %d != %d\n", test.GetTenthsOfMS(), time.GetTenthsOfMS() );
|
||||
}
|
||||
}
|
||||
|
||||
void TestSerialization( const char *pStr, const char *pExpectedStr = NULL, bool bExpectedSuccess = true )
|
||||
{
|
||||
CUtlBuffer buf( pStr, V_strlen( pStr ) + 1, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
|
||||
DmeTime_t time;
|
||||
if ( !Unserialize( buf, time ) )
|
||||
{
|
||||
if ( bExpectedSuccess )
|
||||
{
|
||||
Msg( "TestUnserialize: %s failed\n", pStr );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CUtlBuffer testbuf( 0, 20, CUtlBuffer::TEXT_BUFFER );
|
||||
Serialize( testbuf, time );
|
||||
|
||||
char pTestStr[ 20 ];
|
||||
testbuf.GetString( pTestStr, sizeof( pTestStr ) );
|
||||
|
||||
if ( !pExpectedStr )
|
||||
{
|
||||
pExpectedStr = pStr;
|
||||
}
|
||||
|
||||
if ( V_strcmp( pTestStr, pExpectedStr ) )
|
||||
{
|
||||
Msg( "TestUnserialize: %s != %s\n", pTestStr, pExpectedStr );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CTestTimeSerialization g_testTimeSerialization;
|
||||
|
||||
#endif
|
||||
94
tier1/undiff.cpp
Normal file
94
tier1/undiff.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
//========= Copyright © 1996-2005, 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;
|
||||
|
||||
}
|
||||
182
tier1/uniqueid.cpp
Normal file
182
tier1/uniqueid.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
//====== Copyright © 1996-2005, 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"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.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) && V_isspace( pTemp[nMaxLen] ) )
|
||||
{
|
||||
--nMaxLen;
|
||||
}
|
||||
pTemp[ nMaxLen + 1 ] = 0;
|
||||
|
||||
while( *pTemp && V_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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
1914
tier1/utlbuffer.cpp
Normal file
1914
tier1/utlbuffer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
571
tier1/utlbufferutil.cpp
Normal file
571
tier1/utlbufferutil.cpp
Normal file
@@ -0,0 +1,571 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// $Header: $
|
||||
// $NoKeywords: $
|
||||
//
|
||||
// Serialization buffer
|
||||
//===========================================================================//
|
||||
|
||||
#pragma warning (disable : 4514)
|
||||
|
||||
#include "tier1/utlbufferutil.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "mathlib/vector.h"
|
||||
#include "mathlib/vector2d.h"
|
||||
#include "mathlib/vector4d.h"
|
||||
#include "mathlib/vmatrix.h"
|
||||
#include "color.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "tier1/utlstring.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier1/characterset.h"
|
||||
#include "tier1/utlsymbollarge.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// For serialization, set the delimiter rules
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlCharConversion *s_pConv = NULL;
|
||||
const char *s_pUtlBufferUtilArrayDelim = NULL;
|
||||
void SetSerializationDelimiter( CUtlCharConversion *pConv )
|
||||
{
|
||||
s_pConv = pConv;
|
||||
}
|
||||
|
||||
void SetSerializationArrayDelimiter( const char *pDelimiter )
|
||||
{
|
||||
s_pUtlBufferUtilArrayDelim = pDelimiter;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Serialize a floating point number in text mode in a readably friendly fashion
|
||||
//-----------------------------------------------------------------------------
|
||||
static void SerializeFloat( CUtlBuffer &buf, float f )
|
||||
{
|
||||
Assert( buf.IsText() );
|
||||
|
||||
// FIXME: Print this in a way that we never lose precision
|
||||
char pTemp[256];
|
||||
int nLen = Q_snprintf( pTemp, sizeof(pTemp), "%.10f", f );
|
||||
while ( nLen > 0 && pTemp[nLen-1] == '0' )
|
||||
{
|
||||
--nLen;
|
||||
pTemp[nLen] = 0;
|
||||
}
|
||||
if ( nLen > 0 && pTemp[nLen-1] == '.' )
|
||||
{
|
||||
--nLen;
|
||||
pTemp[nLen] = 0;
|
||||
}
|
||||
buf.PutString( pTemp );
|
||||
}
|
||||
|
||||
static void SerializeFloats( CUtlBuffer &buf, int nCount, const float *pFloats )
|
||||
{
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
SerializeFloat( buf, pFloats[i] );
|
||||
if ( i != nCount-1 )
|
||||
{
|
||||
buf.PutChar( ' ' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Serialization methods for basic types
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Serialize( CUtlBuffer &buf, const bool &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
buf.Printf( "%d", src );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutChar( src );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, bool &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
int nValue = 0;
|
||||
int nRetVal = buf.Scanf( "%d", &nValue );
|
||||
dest = ( nValue != 0 );
|
||||
return (nRetVal == 1) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest = ( buf.GetChar( ) != 0 );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const int &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
buf.Printf( "%d", src );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutInt( src );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, int &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
int nRetVal = buf.Scanf( "%d", &dest );
|
||||
return (nRetVal == 1) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest = buf.GetInt( );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const float &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
SerializeFloat( buf, src );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutFloat( src );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, float &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
// FIXME: Print this in a way that we never lose precision
|
||||
int nRetVal = buf.Scanf( "%f", &dest );
|
||||
return (nRetVal == 1) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest = buf.GetFloat( );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attribute types related to vector math
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Serialize( CUtlBuffer &buf, const Vector2D &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
SerializeFloats( buf, 2, src.Base() );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutFloat( src.x );
|
||||
buf.PutFloat( src.y );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, Vector2D &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
// FIXME: Print this in a way that we never lose precision
|
||||
int nRetVal = buf.Scanf( "%f %f", &dest.x, &dest.y );
|
||||
return (nRetVal == 2) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest.x = buf.GetFloat( );
|
||||
dest.y = buf.GetFloat( );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const Vector &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
SerializeFloats( buf, 3, src.Base() );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutFloat( src.x );
|
||||
buf.PutFloat( src.y );
|
||||
buf.PutFloat( src.z );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, Vector &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
// FIXME: Print this in a way that we never lose precision
|
||||
int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z );
|
||||
return (nRetVal == 3) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest.x = buf.GetFloat( );
|
||||
dest.y = buf.GetFloat( );
|
||||
dest.z = buf.GetFloat( );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const Vector4D &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
SerializeFloats( buf, 4, src.Base() );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutFloat( src.x );
|
||||
buf.PutFloat( src.y );
|
||||
buf.PutFloat( src.z );
|
||||
buf.PutFloat( src.w );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, Vector4D &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
// FIXME: Print this in a way that we never lose precision
|
||||
int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w );
|
||||
return (nRetVal == 4) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest.x = buf.GetFloat( );
|
||||
dest.y = buf.GetFloat( );
|
||||
dest.z = buf.GetFloat( );
|
||||
dest.w = buf.GetFloat( );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const QAngle &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
SerializeFloats( buf, 3, src.Base() );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutFloat( src.x );
|
||||
buf.PutFloat( src.y );
|
||||
buf.PutFloat( src.z );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, QAngle &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
// FIXME: Print this in a way that we never lose precision
|
||||
int nRetVal = buf.Scanf( "%f %f %f", &dest.x, &dest.y, &dest.z );
|
||||
return (nRetVal == 3) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest.x = buf.GetFloat( );
|
||||
dest.y = buf.GetFloat( );
|
||||
dest.z = buf.GetFloat( );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const Quaternion &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
SerializeFloats( buf, 4, &src.x );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutFloat( src.x );
|
||||
buf.PutFloat( src.y );
|
||||
buf.PutFloat( src.z );
|
||||
buf.PutFloat( src.w );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, Quaternion &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
// FIXME: Print this in a way that we never lose precision
|
||||
int nRetVal = buf.Scanf( "%f %f %f %f", &dest.x, &dest.y, &dest.z, &dest.w );
|
||||
QuaternionNormalize( dest );
|
||||
return (nRetVal == 4) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest.x = buf.GetFloat( );
|
||||
dest.y = buf.GetFloat( );
|
||||
dest.z = buf.GetFloat( );
|
||||
dest.w = buf.GetFloat( );
|
||||
QuaternionNormalize( dest );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const VMatrix &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
buf.Printf( "\n" );
|
||||
SerializeFloats( buf, 4, src[0] );
|
||||
buf.Printf( "\n" );
|
||||
SerializeFloats( buf, 4, src[1] );
|
||||
buf.Printf( "\n" );
|
||||
SerializeFloats( buf, 4, src[2] );
|
||||
buf.Printf( "\n" );
|
||||
SerializeFloats( buf, 4, src[3] );
|
||||
buf.Printf( "\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.Put( &src, sizeof(VMatrix) );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, VMatrix &dest )
|
||||
{
|
||||
if ( !buf.IsValid() )
|
||||
return false;
|
||||
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
int nRetVal = buf.Scanf( "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
|
||||
&dest[ 0 ][ 0 ], &dest[ 0 ][ 1 ], &dest[ 0 ][ 2 ], &dest[ 0 ][ 3 ],
|
||||
&dest[ 1 ][ 0 ], &dest[ 1 ][ 1 ], &dest[ 1 ][ 2 ], &dest[ 1 ][ 3 ],
|
||||
&dest[ 2 ][ 0 ], &dest[ 2 ][ 1 ], &dest[ 2 ][ 2 ], &dest[ 2 ][ 3 ],
|
||||
&dest[ 3 ][ 0 ], &dest[ 3 ][ 1 ], &dest[ 3 ][ 2 ], &dest[ 3 ][ 3 ] );
|
||||
return (nRetVal == 16);
|
||||
}
|
||||
|
||||
buf.Get( &dest, sizeof(VMatrix) );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Color attribute
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Serialize( CUtlBuffer &buf, const Color &src )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
buf.Printf( "%d %d %d %d", src[0], src[1], src[2], src[3] );
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.PutUnsignedChar( src[0] );
|
||||
buf.PutUnsignedChar( src[1] );
|
||||
buf.PutUnsignedChar( src[2] );
|
||||
buf.PutUnsignedChar( src[3] );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, Color &dest )
|
||||
{
|
||||
if ( buf.IsText() )
|
||||
{
|
||||
int r = 0, g = 0, b = 0, a = 255;
|
||||
int nRetVal = buf.Scanf( "%d %d %d %d", &r, &g, &b, &a );
|
||||
dest.SetColor( r, g, b, a );
|
||||
return (nRetVal == 4) && buf.IsValid();
|
||||
}
|
||||
|
||||
dest[0] = buf.GetUnsignedChar( );
|
||||
dest[1] = buf.GetUnsignedChar( );
|
||||
dest[2] = buf.GetUnsignedChar( );
|
||||
dest[3] = buf.GetUnsignedChar( );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
/*
|
||||
//-----------------------------------------------------------------------------
|
||||
// Object ID attribute
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Serialize( CUtlBuffer &buf, const DmObjectId_t &src )
|
||||
{
|
||||
return g_pDataModel->Serialize( buf, src );
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, DmObjectId_t &dest )
|
||||
{
|
||||
return g_pDataModel->Unserialize( buf, &dest );
|
||||
}
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Binary buffer attribute
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Serialize( CUtlBuffer &buf, const CUtlBinaryBlock &src )
|
||||
{
|
||||
int nLength = src.Length();
|
||||
if ( !buf.IsText() )
|
||||
{
|
||||
buf.PutInt( nLength );
|
||||
if ( nLength != 0 )
|
||||
{
|
||||
buf.Put( src.Get(), nLength );
|
||||
}
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
// Writes out uuencoded binaries
|
||||
for ( int i = 0; i < nLength; ++i )
|
||||
{
|
||||
if ( (i % 40) == 0 )
|
||||
{
|
||||
buf.PutChar( '\n' );
|
||||
}
|
||||
|
||||
char b1 = src[i] & 0xF;
|
||||
char b2 = src[i] >> 4;
|
||||
|
||||
char c1 = ( b1 <= 9 ) ? b1 + '0' : b1 - 10 + 'A';
|
||||
char c2 = ( b2 <= 9 ) ? b2 + '0' : b2 - 10 + 'A';
|
||||
|
||||
buf.PutChar( c2 );
|
||||
buf.PutChar( c1 );
|
||||
}
|
||||
|
||||
buf.PutChar( '\n' );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
static int CountBinaryBytes( CUtlBuffer &buf, int *pEndGet )
|
||||
{
|
||||
// This counts the number of bytes in the uuencoded text
|
||||
int nStartGet = buf.TellGet();
|
||||
buf.EatWhiteSpace();
|
||||
*pEndGet = buf.TellGet();
|
||||
int nByteCount = 0;
|
||||
while ( buf.IsValid() )
|
||||
{
|
||||
char c1 = buf.GetChar();
|
||||
char c2 = buf.GetChar();
|
||||
|
||||
bool bIsNum1 = ( c1 >= '0' ) && ( c1 <= '9' );
|
||||
bool bIsNum2 = ( c2 >= '0' ) && ( c2 <= '9' );
|
||||
|
||||
bool bIsAlpha1 = (( c1 >= 'A' ) && ( c1 <= 'F' )) || (( c1 >= 'a' ) && ( c1 <= 'f' ));
|
||||
bool bIsAlpha2 = (( c2 >= 'A' ) && ( c2 <= 'F' )) || (( c2 >= 'a' ) && ( c2 <= 'f' ));
|
||||
|
||||
if ( !(bIsNum1 || bIsAlpha1) || !(bIsNum2 || bIsAlpha2) )
|
||||
break;
|
||||
|
||||
buf.EatWhiteSpace();
|
||||
*pEndGet = buf.TellGet();
|
||||
++nByteCount;
|
||||
}
|
||||
buf.SeekGet( CUtlBuffer::SEEK_HEAD, nStartGet );
|
||||
return nByteCount;
|
||||
}
|
||||
|
||||
inline static unsigned char HexCharToInt( int c1 )
|
||||
{
|
||||
if (( c1 >= '0' ) && ( c1 <= '9' ))
|
||||
return c1 - '0';
|
||||
|
||||
if (( c1 >= 'A' ) && ( c1 <= 'F' ))
|
||||
return 10 + c1 - 'A';
|
||||
|
||||
if (( c1 >= 'a' ) && ( c1 <= 'f' ))
|
||||
return 10 + c1 - 'a';
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, CUtlBinaryBlock &dest )
|
||||
{
|
||||
if ( !buf.IsText() )
|
||||
{
|
||||
int nLen = buf.GetInt( );
|
||||
dest.SetLength( nLen );
|
||||
if ( dest.Length() != 0 )
|
||||
{
|
||||
buf.Get( dest.Get(), dest.Length() );
|
||||
}
|
||||
|
||||
if ( nLen != dest.Length() )
|
||||
{
|
||||
buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLen - dest.Length() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
int nEndGet = 0;
|
||||
int nByteCount = CountBinaryBytes( buf, &nEndGet );
|
||||
if ( nByteCount < 0 )
|
||||
return false;
|
||||
|
||||
buf.EatWhiteSpace();
|
||||
int nDest = 0;
|
||||
dest.SetLength( nByteCount );
|
||||
while( buf.TellGet() < nEndGet )
|
||||
{
|
||||
char c1 = buf.GetChar();
|
||||
char c2 = buf.GetChar();
|
||||
|
||||
unsigned char b1 = HexCharToInt( c1 );
|
||||
unsigned char b2 = HexCharToInt( c2 );
|
||||
if ( b1 == 0xFF || b2 == 0xFF )
|
||||
return false;
|
||||
|
||||
dest[ nDest++ ] = b2 | ( b1 << 4 );
|
||||
buf.EatWhiteSpace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// String attribute
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Serialize( CUtlBuffer &buf, const CUtlString &src )
|
||||
{
|
||||
buf.PutDelimitedString( s_pConv, src.Get() );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
bool Unserialize( CUtlBuffer &buf, CUtlString &dest )
|
||||
{
|
||||
int nLen = buf.PeekDelimitedStringLength( s_pConv );
|
||||
dest.SetLength( nLen - 1 ); // -1 because the length returned includes space for \0
|
||||
buf.GetDelimitedString( s_pConv, dest.Get(), nLen );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
|
||||
bool Serialize( CUtlBuffer &buf, const CUtlSymbolLarge &src )
|
||||
{
|
||||
// Serialization of symbols is allowed, but it writes that string of the symbol,
|
||||
// not the symbol index. This is done so that text serialization of symbols will write
|
||||
// the actual string and so that functions which rely on text serialization to convert
|
||||
// an attribute value to text will get the proper string for the symbol.
|
||||
buf.PutDelimitedString( s_pConv, src.String() );
|
||||
return buf.IsValid();
|
||||
}
|
||||
|
||||
|
||||
1113
tier1/utlsoacontainer.cpp
Normal file
1113
tier1/utlsoacontainer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1214
tier1/utlstring.cpp
Normal file
1214
tier1/utlstring.cpp
Normal file
File diff suppressed because it is too large
Load Diff
13
tier1/utlstringtoken.cpp
Normal file
13
tier1/utlstringtoken.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "utlstringtoken.h"
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
523
tier1/utlsymbol.cpp
Normal file
523
tier1/utlsymbol.cpp
Normal file
@@ -0,0 +1,523 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Defines a symbol table
|
||||
//
|
||||
// $Header: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#pragma warning (disable:4514)
|
||||
|
||||
#include "utlsymbol.h"
|
||||
#include "tier0/threadtools.h"
|
||||
#include "stringpool.h"
|
||||
#include "generichash.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include <stddef.h>
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
void CUtlSymbol::LockTableForRead()
|
||||
{
|
||||
Initialize();
|
||||
s_pSymbolTable->LockForRead();
|
||||
}
|
||||
|
||||
void CUtlSymbol::UnlockTableForRead()
|
||||
{
|
||||
s_pSymbolTable->UnlockForRead();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
||||
|
||||
const char* CUtlSymbol::StringNoLock( ) const
|
||||
{
|
||||
return CurrTable()->StringNoLock(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::DecoratedStringFromIndex( const CStringPoolIndex &index ) const
|
||||
{
|
||||
Assert( index.m_iPool < m_StringPools.Count() );
|
||||
Assert( index.m_iOffset < m_StringPools[index.m_iPool]->m_TotalLen );
|
||||
|
||||
// step over the hash decorating the beginning of the string
|
||||
return (&m_StringPools[index.m_iPool]->m_Data[index.m_iOffset]);
|
||||
}
|
||||
|
||||
inline const char* CUtlSymbolTable::StringFromIndex( const CStringPoolIndex &index ) const
|
||||
{
|
||||
// step over the hash decorating the beginning of the string
|
||||
return DecoratedStringFromIndex(index)+sizeof(hashDecoration_t);
|
||||
}
|
||||
|
||||
// The first two bytes of each string in the pool are actually the hash for that string.
|
||||
// Thus we compare hashes rather than entire strings for a significant perf benefit.
|
||||
// However since there is a high rate of hash collision we must still compare strings
|
||||
// if the hashes match.
|
||||
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 );
|
||||
|
||||
#if 1 // using the hashes
|
||||
const char *str1, *str2;
|
||||
hashDecoration_t hash1, hash2;
|
||||
|
||||
if (i1 == INVALID_STRING_INDEX)
|
||||
{
|
||||
str1 = pTable->m_pUserSearchString;
|
||||
hash1 = pTable->m_nUserSearchStringHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
str1 = pTable->DecoratedStringFromIndex( i1 );
|
||||
hashDecoration_t storedHash = *reinterpret_cast<const hashDecoration_t *>(str1);
|
||||
str1 += sizeof(hashDecoration_t);
|
||||
AssertMsg2( storedHash == ( !pTable->m_bInsensitive ? HashString(str1) : HashStringCaseless(str1) ),
|
||||
"The stored hash (%d) for symbol %s is not correct.", storedHash, str1 );
|
||||
hash1 = storedHash;
|
||||
}
|
||||
|
||||
if (i2 == INVALID_STRING_INDEX)
|
||||
{
|
||||
str2 = pTable->m_pUserSearchString;
|
||||
hash2 = pTable->m_nUserSearchStringHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
str2 = pTable->DecoratedStringFromIndex( i2 );
|
||||
hashDecoration_t storedHash = *reinterpret_cast<const hashDecoration_t *>(str2);
|
||||
str2 += sizeof(hashDecoration_t);
|
||||
AssertMsg2( storedHash == ( !pTable->m_bInsensitive ? HashString(str2) : HashStringCaseless(str2) ),
|
||||
"The stored hash (%d) for symbol '%s' is not correct.", storedHash, str2 );
|
||||
hash2 = storedHash;
|
||||
}
|
||||
|
||||
// compare the hashes
|
||||
if ( hash1 == hash2 )
|
||||
{
|
||||
if ( !str1 && str2 )
|
||||
return 1;
|
||||
if ( !str2 && str1 )
|
||||
return -1;
|
||||
if ( !str1 && !str2 )
|
||||
return 0;
|
||||
|
||||
// if the hashes match compare the strings
|
||||
if ( !pTable->m_bInsensitive )
|
||||
return strcmp( str1, str2 ) < 0;
|
||||
else
|
||||
return V_stricmp( str1, str2 ) < 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return hash1 < hash2;
|
||||
}
|
||||
|
||||
#else // not using the hashes, just comparing strings
|
||||
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 1;
|
||||
if ( !str2 && str1 )
|
||||
return -1;
|
||||
if ( !str1 && !str2 )
|
||||
return 0;
|
||||
if ( !pTable->m_bInsensitive )
|
||||
return strcmp( str1, str2 ) < 0;
|
||||
else
|
||||
return strcmpi( str1, str2 ) < 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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
|
||||
{
|
||||
VPROF( "CUtlSymbol::Find" );
|
||||
if (!pString)
|
||||
return CUtlSymbol();
|
||||
|
||||
// Store a special context used to help with insertion
|
||||
m_pUserSearchString = pString;
|
||||
m_nUserSearchStringHash = m_bInsensitive ? HashStringCaseless(pString) : HashString(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;
|
||||
m_nUserSearchStringHash = 0;
|
||||
#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 )
|
||||
{
|
||||
VPROF("CUtlSymbol::AddString");
|
||||
if (!pString)
|
||||
return CUtlSymbol( UTL_INVAL_SYMBOL );
|
||||
|
||||
CUtlSymbol id = Find( pString );
|
||||
|
||||
if (id.IsValid())
|
||||
return id;
|
||||
|
||||
int lenString = strlen(pString) + 1; // length of just the string
|
||||
int lenDecorated = lenString + sizeof(hashDecoration_t); // and with its hash decoration
|
||||
// make sure that all strings are aligned on 2-byte boundaries so the hashes will read correctly
|
||||
COMPILE_TIME_ASSERT(sizeof(hashDecoration_t) == 2);
|
||||
lenDecorated = (lenDecorated + 1) & (~0x01); // round up to nearest multiple of 2
|
||||
|
||||
// Find a pool with space for this string, or allocate a new one.
|
||||
int iPool = FindPoolWithSpace( lenDecorated );
|
||||
if ( iPool == -1 )
|
||||
{
|
||||
// Add a new pool.
|
||||
int newPoolSize = MAX( lenDecorated + sizeof( StringPool_t ), MIN_STRING_POOL_SIZE );
|
||||
StringPool_t *pPool = (StringPool_t*)malloc( newPoolSize );
|
||||
pPool->m_TotalLen = newPoolSize - sizeof( StringPool_t );
|
||||
pPool->m_SpaceUsed = 0;
|
||||
iPool = m_StringPools.AddToTail( pPool );
|
||||
}
|
||||
|
||||
// Compute a hash
|
||||
hashDecoration_t hash = m_bInsensitive ? HashStringCaseless(pString) : HashString(pString) ;
|
||||
|
||||
// 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;
|
||||
const char *startingAddr = &pPool->m_Data[pPool->m_SpaceUsed];
|
||||
|
||||
// store the hash at the head of the string
|
||||
*((hashDecoration_t *)(startingAddr)) = hash;
|
||||
// and then the string's data
|
||||
memcpy( (void *)(startingAddr + sizeof(hashDecoration_t)), pString, lenString );
|
||||
pPool->m_SpaceUsed += lenDecorated;
|
||||
|
||||
// insert the string into the vector.
|
||||
CStringPoolIndex index;
|
||||
index.m_iPool = iPool;
|
||||
index.m_iOffset = iStringOffset;
|
||||
|
||||
MEM_ALLOC_CREDIT();
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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
|
||||
strlwr( 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.SetPath( m_PathStringPool.FindStringHandle( basepath ) );
|
||||
handle.SetFile( m_FileStringPool.FindStringHandle( filename ) );
|
||||
if ( handle.GetPath() && handle.GetFile() )
|
||||
{
|
||||
// found
|
||||
m_lock.UnlockWrite();
|
||||
return *( FileNameHandle_t * )( &handle );
|
||||
}
|
||||
|
||||
// safely add it
|
||||
handle.SetPath( m_PathStringPool.ReferenceStringHandle( basepath ) );
|
||||
handle.SetFile( m_FileStringPool.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
|
||||
strlwr( 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;
|
||||
|
||||
m_lock.LockForRead();
|
||||
handle.SetPath( m_PathStringPool.FindStringHandle( basepath ) );
|
||||
handle.SetFile( m_FileStringPool.FindStringHandle( filename ) );
|
||||
m_lock.UnlockRead();
|
||||
|
||||
|
||||
if ( ( handle.GetPath() == 0 ) || ( handle.GetFile() == 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 *internalFileHandle = ( FileNameHandleInternal_t * )&handle;
|
||||
if ( !internalFileHandle )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock.LockForRead();
|
||||
const char *path = m_PathStringPool.HandleToString( internalFileHandle->GetPath() );
|
||||
const char *fn = m_FileStringPool.HandleToString( internalFileHandle->GetFile() );
|
||||
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_PathStringPool.FreeAll();
|
||||
m_FileStringPool.FreeAll();
|
||||
}
|
||||
|
||||
void CUtlFilenameSymbolTable::SpewStrings()
|
||||
{
|
||||
m_lock.LockForRead();
|
||||
m_PathStringPool.SpewStrings();
|
||||
m_FileStringPool.SpewStrings();
|
||||
m_lock.UnlockRead();
|
||||
}
|
||||
|
||||
bool CUtlFilenameSymbolTable::SaveToBuffer( CUtlBuffer &buffer )
|
||||
{
|
||||
m_lock.LockForRead();
|
||||
bool bResult = m_PathStringPool.SaveToBuffer( buffer );
|
||||
bResult = bResult && m_FileStringPool.SaveToBuffer( buffer );
|
||||
m_lock.UnlockRead();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool CUtlFilenameSymbolTable::RestoreFromBuffer( CUtlBuffer &buffer )
|
||||
{
|
||||
m_lock.LockForWrite();
|
||||
bool bResult = m_PathStringPool.RestoreFromBuffer( buffer );
|
||||
bResult = bResult && m_FileStringPool.RestoreFromBuffer( buffer );
|
||||
m_lock.UnlockWrite();
|
||||
|
||||
return bResult;
|
||||
}
|
||||
1
tier1/vsi.nul
Normal file
1
tier1/vsi.nul
Normal file
@@ -0,0 +1 @@
|
||||
IMPORTANT: Do not remove the custom build step for this file
|
||||
Reference in New Issue
Block a user