This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+41
View 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++;
}
}
+182
View File
@@ -0,0 +1,182 @@
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Generic CRC functions
//
//=============================================================================//
#include "tier0/platform.h"
#include "commonmacros.h"
#include "checksum_crc.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define CRC32_INIT_VALUE 0xFFFFFFFFUL
#define CRC32_XOR_VALUE 0xFFFFFFFFUL
#define NUM_BYTES 256
static const CRC32_t pulCRCTable[NUM_BYTES] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
void CRC32_Init(CRC32_t *pulCRC)
{
*pulCRC = CRC32_INIT_VALUE;
}
void CRC32_Final(CRC32_t *pulCRC)
{
*pulCRC ^= CRC32_XOR_VALUE;
}
CRC32_t CRC32_GetTableEntry( unsigned int slot )
{
return pulCRCTable[(unsigned char)slot];
}
void CRC32_ProcessBuffer(CRC32_t *pulCRC, const void *pBuffer, int nBuffer)
{
CRC32_t ulCrc = *pulCRC;
unsigned char *pb = (unsigned char *)pBuffer;
unsigned int nFront;
int nMain;
JustAfew:
switch (nBuffer)
{
case 7:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 6:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 5:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 4:
ulCrc ^= LittleLong( *(CRC32_t *)pb );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
*pulCRC = ulCrc;
return;
case 3:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 2:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 1:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 0:
*pulCRC = ulCrc;
return;
}
// We may need to do some alignment work up front, and at the end, so that
// the main loop is aligned and only has to worry about 8 byte at a time.
//
// The low-order two bits of pb and nBuffer in total control the
// upfront work.
//
nFront = ((unsigned int)pb) & 3;
nBuffer -= nFront;
switch (nFront)
{
case 3:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 2:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
case 1:
ulCrc = pulCRCTable[*pb++ ^ (unsigned char)ulCrc] ^ (ulCrc >> 8);
}
nMain = nBuffer >> 3;
while (nMain--)
{
ulCrc ^= LittleLong( *(CRC32_t *)pb );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc ^= LittleLong( *(CRC32_t *)(pb + 4) );
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
ulCrc = pulCRCTable[(unsigned char)ulCrc] ^ (ulCrc >> 8);
pb += 8;
}
nBuffer &= 7;
goto JustAfew;
}
+291
View File
@@ -0,0 +1,291 @@
//===== 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
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 );
V_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
}
+1521
View File
File diff suppressed because it is too large Load Diff
+501
View File
@@ -0,0 +1,501 @@
//===== Copyright 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( (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 ( isdigit( token ) )
{
int i = 0;
m_Identifier[i++] = token;
while( 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 ( 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;
}
// SECURIY: Because this starts one character late, it picks up the null termination from pInfixExpression.
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;
}
+429
View File
@@ -0,0 +1,429 @@
//======= 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"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//
// Table of randomly shuffled values from 0-255 generated by:
//
//-----------------------------------------------------------------------------
/*
void MakeRandomValues()
{
int i, j, r;
unsigned t;
srand( 0xdeadbeef );
for ( i = 0; i < 256; i++ )
{
g_nRandomValues[i] = (unsigned )i;
}
for (j = 0; j < 8; j++)
{
for (i = 0; i < 256; i++)
{
r = rand() & 0xff;
t = g_nRandomValues[i];
g_nRandomValues[i] = g_nRandomValues[r];
g_nRandomValues[r] = t;
}
}
printf("static unsigned g_nRandomValues[256] =\n{\n");
for (i = 0; i < 256; i += 16)
{
printf("\t");
for (j = 0; j < 16; j++)
printf(" %3d,", g_nRandomValues[i+j]);
printf("\n");
}
printf("};\n");
}
*/
static unsigned g_nRandomValues[256] =
{
238, 164, 191, 168, 115, 16, 142, 11, 213, 214, 57, 151, 248, 252, 26, 198,
13, 105, 102, 25, 43, 42, 227, 107, 210, 251, 86, 66, 83, 193, 126, 108,
131, 3, 64, 186, 192, 81, 37, 158, 39, 244, 14, 254, 75, 30, 2, 88,
172, 176, 255, 69, 0, 45, 116, 139, 23, 65, 183, 148, 33, 46, 203, 20,
143, 205, 60, 197, 118, 9, 171, 51, 233, 135, 220, 49, 71, 184, 82, 109,
36, 161, 169, 150, 63, 96, 173, 125, 113, 67, 224, 78, 232, 215, 35, 219,
79, 181, 41, 229, 149, 153, 111, 217, 21, 72, 120, 163, 133, 40, 122, 140,
208, 231, 211, 200, 160, 182, 104, 110, 178, 237, 15, 101, 27, 50, 24, 189,
177, 130, 187, 92, 253, 136, 100, 212, 19, 174, 70, 22, 170, 206, 162, 74,
247, 5, 47, 32, 179, 117, 132, 195, 124, 123, 245, 128, 236, 223, 12, 84,
54, 218, 146, 228, 157, 94, 106, 31, 17, 29, 194, 34, 56, 134, 239, 246,
241, 216, 127, 98, 7, 204, 154, 152, 209, 188, 48, 61, 87, 97, 225, 85,
90, 167, 155, 112, 145, 114, 141, 93, 250, 4, 201, 156, 38, 89, 226, 196,
1, 235, 44, 180, 159, 121, 119, 166, 190, 144, 10, 91, 76, 230, 221, 80,
207, 55, 58, 53, 175, 8, 6, 52, 68, 242, 18, 222, 103, 249, 147, 129,
138, 243, 28, 185, 62, 59, 240, 202, 234, 99, 77, 73, 199, 137, 95, 165,
};
//-----------------------------------------------------------------------------
// String
//-----------------------------------------------------------------------------
unsigned FASTCALL HashString( const char *pszKey )
{
const uint8 *k = (const uint8 *)pszKey;
unsigned even = 0,
odd = 0,
n;
while ((n = *k++) != 0)
{
even = g_nRandomValues[odd ^ n];
if ((n = *k++) != 0)
odd = g_nRandomValues[even ^ n];
else
break;
}
return (even << 8) | odd ;
}
//-----------------------------------------------------------------------------
// Case-insensitive string
//-----------------------------------------------------------------------------
unsigned FASTCALL HashStringCaseless( const char *pszKey )
{
const uint8 *k = (const uint8 *) pszKey;
unsigned even = 0,
odd = 0,
n;
while ((n = toupper(*k++)) != 0)
{
even = g_nRandomValues[odd ^ n];
if ((n = toupper(*k++)) != 0)
odd = g_nRandomValues[even ^ n];
else
break;
}
return (even << 8) | odd;
}
//-----------------------------------------------------------------------------
// 32 bit conventional case-insensitive string
//-----------------------------------------------------------------------------
unsigned FASTCALL HashStringCaselessConventional( const char *pszKey )
{
unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add
for( ; *pszKey ; pszKey++ )
{
hash = ( ( hash << 5 ) + hash ) + (uint8)tolower(*pszKey);
}
return hash;
}
//-----------------------------------------------------------------------------
// int hash
//-----------------------------------------------------------------------------
unsigned FASTCALL HashInt( const int n )
{
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 )
{
const uint32 * p = (const uint32 *) pKey;
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 )
{
const uint32 * p = (const uint32 *) pKey;
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 )
{
const uint32 * p = (const uint32 *) pKey;
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 )
{
const uint32 * p = (const uint32 *) pKey;
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 = 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;
}
+705
View File
@@ -0,0 +1,705 @@
//===== 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)
return LoadLibrary( pName );
#else
return LoadLibraryEx( pName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
#endif
}
unsigned 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;
V_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;
V_strncpy( str, pLibraryName, sizeof(str) );
if ( !V_stristr( str, pModuleExtension ) )
{
if ( IsX360() )
{
V_StripExtension( str, str, sizeof(str) );
}
V_strncat( str, pModuleAddition, sizeof(str) );
}
V_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 ( !V_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 PATCH path if patched
if ( g_pPS3PathInfo->IsPatched() )
{
V_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/bin/%s",
g_pPS3PathInfo->GamePatchBasePath(), pModuleName );
hDLL = Sys_LoadLibrary( szAbsoluteModuleName );
}
if ( !hDLL ) // use base PRX path
{
V_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
V_snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName );
}
else
{
V_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 )
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;
}
}
+3427
View File
File diff suppressed because it is too large Load Diff
+336
View File
@@ -0,0 +1,336 @@
//===== 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
{
// Free everything..
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 nOffset = (intp)pMem - (intp)pCur->m_Data;
return ( nOffset % m_BlockSize ) == 0;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Reports memory leaks
//-----------------------------------------------------------------------------
void CUtlMemoryPool::ReportLeaks()
{
if (!g_ReportFunc)
return;
g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated);
#ifdef _DEBUG
// walk and destroy the free list so it doesn't intefere in the scan
while (m_pHeadOfFreeList != NULL)
{
void *next = *((void**)m_pHeadOfFreeList);
memset(m_pHeadOfFreeList, 0, m_BlockSize);
m_pHeadOfFreeList = next;
}
g_ReportFunc("Dumping memory: \'");
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
{
// scan the memory block and dump the leaks
char *scanPoint = (char *)pCur->m_Data;
char *scanEnd = pCur->m_Data + pCur->m_NumBytes;
bool needSpace = false;
while (scanPoint < scanEnd)
{
// search for and dump any strings
if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint))
{
g_ReportFunc("%c", *scanPoint);
needSpace = true;
}
else if (needSpace)
{
needSpace = false;
g_ReportFunc(" ");
}
scanPoint++;
}
}
g_ReportFunc("\'\n");
#endif // _DEBUG
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CUtlMemoryPool::AddNewBlob()
{
MEM_ALLOC_CREDIT_(m_pszAllocOwner);
int sizeMultiplier;
if( m_GrowMode == GROW_SLOW )
{
sizeMultiplier = 1;
}
else
{
if ( m_GrowMode == GROW_NONE )
{
// Can only have one allocation when we're in this mode
if( m_NumBlobs != 0 )
{
Assert( !"CUtlMemoryPool::AddNewBlob: mode == GROW_NONE" );
return;
}
}
// GROW_FAST and GROW_NONE use this.
sizeMultiplier = m_NumBlobs + 1;
}
// maybe use something other than malloc?
int nElements = m_BlocksPerBlob * sizeMultiplier;
int blobSize = m_BlockSize * nElements;
CBlob *pBlob = (CBlob*)malloc( sizeof(CBlob) - 1 + blobSize + ( m_nAlignment - 1 ) );
Assert( pBlob );
// Link it in at the end of the blob list.
pBlob->m_NumBytes = blobSize;
pBlob->m_pNext = &m_BlobHead;
pBlob->m_pPrev = pBlob->m_pNext->m_pPrev;
pBlob->m_pNext->m_pPrev = pBlob->m_pPrev->m_pNext = pBlob;
// setup the free list
m_pHeadOfFreeList = AlignValue( pBlob->m_Data, m_nAlignment );
Assert (m_pHeadOfFreeList);
void **newBlob = (void**)m_pHeadOfFreeList;
for (int j = 0; j < nElements-1; j++)
{
newBlob[0] = (char*)newBlob + m_BlockSize;
newBlob = (void**)newBlob[0];
}
// null terminate list
newBlob[0] = NULL;
m_NumBlobs++;
}
void* CUtlMemoryPool::Alloc()
{
return Alloc( m_BlockSize );
}
void* CUtlMemoryPool::AllocZero()
{
return AllocZero( m_BlockSize );
}
//-----------------------------------------------------------------------------
// Purpose: Allocs a single block of memory from the pool.
// Input : amount -
//-----------------------------------------------------------------------------
void *CUtlMemoryPool::Alloc( size_t amount )
{
void *returnBlock;
if ( amount > (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, 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;
}
+641
View File
@@ -0,0 +1,641 @@
//========= Copyright 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);
//-----------------------------------------------------------------------------
CMemoryStack::CMemoryStack()
: m_pBase( NULL ),
m_pNextAlloc( NULL ),
m_pAllocLimit( NULL ),
m_pCommitLimit( NULL ),
m_alignment( 16 ),
#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE
m_commitSize( 0 ),
m_minCommit( 0 ),
#ifdef _PS3
m_pVirtualMemorySection( NULL ),
#endif
#endif
m_maxSize( 0 ),
m_bRegisteredAllocation( false )
{
m_pszAllocOwner = strdup( "CMemoryStack unattributed" );
}
//-------------------------------------
CMemoryStack::~CMemoryStack()
{
if ( m_pBase )
Term();
free( m_pszAllocOwner );
}
//-------------------------------------
bool CMemoryStack::Init( const char *pszAllocOwner, unsigned maxSize, unsigned commitSize, 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 ( commitSize != 0 )
{
m_commitSize = commitSize;
}
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_commitSize == 0 )
{
m_commitSize = pageSize;
}
else
{
m_commitSize = AlignValue( m_commitSize, pageSize );
}
m_maxSize = AlignValue( m_maxSize, m_commitSize );
Assert( m_maxSize % pageSize == 0 && m_commitSize % pageSize == 0 && m_commitSize <= m_maxSize );
#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_commitSize );
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_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_commitSize = 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;
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_pCommitLimit = m_pBase = NULL;
m_maxSize = 0;
RegisterDeallocation(true);
}
}
//-------------------------------------
int CMemoryStack::GetSize()
{
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_commitSize );
ptrdiff_t commitSize = pNewCommitLimit - m_pCommitLimit;
if( m_pCommitLimit + commitSize > m_pAllocLimit )
{
return false;
}
if ( pNewCommitLimit > m_pCommitLimit )
{
RegisterDeallocation(false);
bool bAllocationSucceeded = false;
#ifdef _WIN32
bAllocationSucceeded = !!VirtualAlloc( m_pCommitLimit, commitSize, VA_COMMIT_FLAGS, PAGE_READWRITE );
#else
bAllocationSucceeded = m_pVirtualMemorySection->CommitPages( m_pCommitLimit, commitSize );
#endif
if ( !bAllocationSucceeded )
{
#if !defined( NO_MALLOC_OVERRIDE )
g_pMemAlloc->OutOfMemory( commitSize );
#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_commitSize );
}
if ( pNewCommitLimit < m_pCommitLimit )
{
RegisterDeallocation(false);
ptrdiff_t decommitSize = m_pCommitLimit - pNewCommitLimit;
#ifdef _WIN32
VirtualFree( pNewCommitLimit, decommitSize, MEM_DECOMMIT );
#else
m_pVirtualMemorySection->DecommitPages( pNewCommitLimit, decommitSize );
#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 || !V_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);
}
//-------------------------------------
void CMemoryStack::PrintContents()
{
Msg( "Total used memory: %d\n", GetUsed() );
Msg( "Total committed memory: %d\n", GetSize() );
}
#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
+91
View File
@@ -0,0 +1,91 @@
//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. =================
//
//
//
//==================================================================================================
#include "strtools.h"
#include "utlvector.h"
CSplitString::CSplitString(const char *pString, const char **pSeparators, int nSeparators)
{
Construct(pString, pSeparators, nSeparators);
};
CSplitString::CSplitString( const char *pString, const char *pSeparator)
{
Construct( pString, &pSeparator, 1 );
}
CSplitString::~CSplitString()
{
if(m_szBuffer)
delete [] m_szBuffer;
}
void CSplitString::Construct( const char *pString, const char **pSeparators, int nSeparators )
{
//////////////////////////////////////////////////////////////////////////
// make a duplicate of the original string. We'll use pieces of this duplicate to tokenize the string
// and create NULL-terminated tokens of the original string
//
int nOriginalStringLength = V_strlen(pString);
m_szBuffer = new char[nOriginalStringLength + 1];
memcpy(m_szBuffer, pString, nOriginalStringLength + 1);
this->Purge();
const char *pCurPos = pString;
while ( 1 )
{
int iFirstSeparator = -1;
const char *pFirstSeparator = 0;
for ( int i=0; i < nSeparators; i++ )
{
const char *pTest = V_stristr( pCurPos, pSeparators[i] );
if ( pTest && (!pFirstSeparator || pTest < pFirstSeparator) )
{
iFirstSeparator = i;
pFirstSeparator = pTest;
}
}
if ( pFirstSeparator )
{
// Split on this separator and continue on.
int separatorLen = strlen( pSeparators[iFirstSeparator] );
if ( pFirstSeparator > pCurPos )
{
//////////////////////////////////////////////////////////////////////////
/// Cut the token out of the duplicate string
char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString);
int nTokenLength = pFirstSeparator-pCurPos;
Assert(nTokenLength > 0 && !memcmp(pTokenInDuplicate,pCurPos,nTokenLength));
pTokenInDuplicate[nTokenLength] = '\0';
this->AddToTail( pTokenInDuplicate /*AllocString( pCurPos, pFirstSeparator-pCurPos )*/ );
}
pCurPos = pFirstSeparator + separatorLen;
}
else
{
// Copy the rest of the string
if ( int nTokenLength = strlen( pCurPos ) )
{
//////////////////////////////////////////////////////////////////////////
// There's no need to cut this token, because there's no separator after it.
// just add its copy in the buffer to the tail
char *pTokenInDuplicate = m_szBuffer + (pCurPos - pString);
Assert(!memcmp(pTokenInDuplicate, pCurPos, nTokenLength));
this->AddToTail( pTokenInDuplicate/*AllocString( pCurPos, -1 )*/ );
}
return;
}
}
}
void CSplitString::PurgeAndDeleteElements()
{
Purge();
}
+426
View File
@@ -0,0 +1,426 @@
//===== 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 ( V_stricmp( pszLeft, pszRight) < 0 );
}
bool StrLessSensitive( const char * const &pszLeft, const char * const &pszRight )
{
return ( V_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();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CCountedStringPool::CCountedStringPool( StringPoolCase_t caseSensitivity )
{
MEM_ALLOC_CREDIT();
m_HashTable.EnsureCount(HASH_TABLE_SIZE);
for( int i = 0; i < m_HashTable.Count(); i++ )
{
m_HashTable[i] = INVALID_ELEMENT;
}
m_FreeListStart = INVALID_ELEMENT;
m_Elements.AddToTail();
m_Elements[0].pString = NULL;
m_Elements[0].nReferenceCount = 0;
m_Elements[0].nNextElement = INVALID_ELEMENT;
m_caseSensitivity = caseSensitivity;
}
CCountedStringPool::~CCountedStringPool()
{
FreeAll();
}
void CCountedStringPool::FreeAll()
{
int i;
// Reset the hash table:
for( i = 0; i < m_HashTable.Count(); i++ )
{
m_HashTable[i] = INVALID_ELEMENT;
}
// Blow away the free list:
m_FreeListStart = INVALID_ELEMENT;
for( i = 0; i < m_Elements.Count(); i++ )
{
if( m_Elements[i].pString )
{
delete [] m_Elements[i].pString;
m_Elements[i].pString = NULL;
m_Elements[i].nReferenceCount = 0;
m_Elements[i].nNextElement = INVALID_ELEMENT;
}
}
// Remove all but the invalid element:
m_Elements.RemoveAll();
m_Elements.AddToTail();
m_Elements[0].pString = NULL;
m_Elements[0].nReferenceCount = 0;
m_Elements[0].nNextElement = INVALID_ELEMENT;
}
unsigned CCountedStringPool::Hash( const char *pszKey )
{
if ( m_caseSensitivity == StringPoolCaseInsensitive )
{
return HashStringCaseless( pszKey );
}
return HashString( pszKey );
}
unsigned short CCountedStringPool::FindStringHandle( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return INVALID_ELEMENT;
unsigned short nHashBucketIndex = ( Hash( pIntrinsic ) %HASH_TABLE_SIZE);
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// Does the bucket already exist?
if( nCurrentBucket != INVALID_ELEMENT )
{
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !V_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
return nCurrentBucket;
}
}
}
return 0;
}
char* CCountedStringPool::FindString( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return NULL;
// Yes, this will be NULL on failure.
return m_Elements[FindStringHandle(pIntrinsic)].pString;
}
unsigned short CCountedStringPool::ReferenceStringHandle( const char* pIntrinsic )
{
if( pIntrinsic == NULL )
return INVALID_ELEMENT;
unsigned short nHashBucketIndex = ( Hash( pIntrinsic ) % HASH_TABLE_SIZE);
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// Does the bucket already exist?
if( nCurrentBucket != INVALID_ELEMENT )
{
for( ; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !V_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
// Anyone who hits 65k references is permanant
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
{
m_Elements[nCurrentBucket].nReferenceCount ++ ;
}
return nCurrentBucket;
}
}
}
if( m_FreeListStart != INVALID_ELEMENT )
{
nCurrentBucket = m_FreeListStart;
m_FreeListStart = m_Elements[nCurrentBucket].nNextElement;
}
else
{
nCurrentBucket = m_Elements.AddToTail();
}
m_Elements[nCurrentBucket].nReferenceCount = 1;
// Insert at the beginning of the bucket:
m_Elements[nCurrentBucket].nNextElement = m_HashTable[ nHashBucketIndex ];
m_HashTable[ nHashBucketIndex ] = nCurrentBucket;
m_Elements[nCurrentBucket].pString = new char[V_strlen( pIntrinsic ) + 1];
V_strcpy( m_Elements[nCurrentBucket].pString, pIntrinsic );
return nCurrentBucket;
}
char* CCountedStringPool::ReferenceString( const char* pIntrinsic )
{
if(!pIntrinsic)
return NULL;
return m_Elements[ReferenceStringHandle( pIntrinsic)].pString;
}
void CCountedStringPool::DereferenceString( const char* pIntrinsic )
{
// If we get a NULL pointer, just return
if (!pIntrinsic)
return;
unsigned short nHashBucketIndex = (Hash( pIntrinsic ) % m_HashTable.Count());
unsigned short nCurrentBucket = m_HashTable[ nHashBucketIndex ];
// If there isn't anything in the bucket, just return.
if ( nCurrentBucket == INVALID_ELEMENT )
return;
for( unsigned short previous = INVALID_ELEMENT; nCurrentBucket != INVALID_ELEMENT ; nCurrentBucket = m_Elements[nCurrentBucket].nNextElement )
{
if( !V_stricmp( pIntrinsic, m_Elements[nCurrentBucket].pString ) )
{
// Anyone who hits 65k references is permanant
if( m_Elements[nCurrentBucket].nReferenceCount < MAX_REFERENCE )
{
m_Elements[nCurrentBucket].nReferenceCount --;
}
if( m_Elements[nCurrentBucket].nReferenceCount == 0 )
{
if( previous == INVALID_ELEMENT )
{
m_HashTable[nHashBucketIndex] = m_Elements[nCurrentBucket].nNextElement;
}
else
{
m_Elements[previous].nNextElement = m_Elements[nCurrentBucket].nNextElement;
}
delete [] m_Elements[nCurrentBucket].pString;
m_Elements[nCurrentBucket].pString = NULL;
m_Elements[nCurrentBucket].nReferenceCount = 0;
m_Elements[nCurrentBucket].nNextElement = m_FreeListStart;
m_FreeListStart = nCurrentBucket;
break;
}
}
previous = nCurrentBucket;
}
}
char* CCountedStringPool::HandleToString( unsigned short handle )
{
return m_Elements[handle].pString;
}
void CCountedStringPool::SpewStrings()
{
int i;
for ( i = 0; i < m_Elements.Count(); i++ )
{
char* string;
string = m_Elements[i].pString;
Msg("String %d: ref:%d %s\n", i, m_Elements[i].nReferenceCount, string == NULL? "EMPTY - ok for slot zero only!" : string);
}
Msg("\n%d total counted strings.", m_Elements.Count());
}
#ifdef _DEBUG
CON_COMMAND( test_stringpool, "Tests the class CStringPool" )
{
CStringPool pool;
Assert(pool.Count() == 0);
pool.Allocate("test");
Assert(pool.Count() == 1);
pool.Allocate("test");
Assert(pool.Count() == 1);
pool.Allocate("test2");
Assert(pool.Count() == 2);
Assert( pool.Find("test2") != NULL );
Assert( pool.Find("TEST") != NULL );
Assert( pool.Find("Test2") != NULL );
Assert( pool.Find("test") != NULL );
pool.FreeAll();
Assert(pool.Count() == 0);
Msg("Pass.");
}
#endif
#define STRING_POOL_VERSION MAKEID( 'C', 'S', 'P', '1' )
#define MAX_STRING_SAVE 1024
bool CCountedStringPool::SaveToBuffer( CUtlBuffer &buffer )
{
if ( m_Elements.Count() <= 1 )
{
// pool is empty, saving nothing
// caller can check put position of buffer to detect
return true;
}
// signature/version
buffer.PutInt( STRING_POOL_VERSION );
buffer.PutUnsignedShort( m_FreeListStart );
buffer.PutInt( m_HashTable.Count() );
for ( int i = 0; i < m_HashTable.Count(); i++ )
{
buffer.PutUnsignedShort( m_HashTable[i] );
}
buffer.PutInt( m_Elements.Count() );
for ( int i = 1; i < m_Elements.Count(); i++ )
{
buffer.PutUnsignedShort( m_Elements[i].nNextElement );
buffer.PutUnsignedChar( m_Elements[i].nReferenceCount );
const char *pString = m_Elements[i].pString;
if ( strlen( pString ) >= MAX_STRING_SAVE )
{
return false;
}
buffer.PutString( pString ? pString : "" );
}
return buffer.IsValid();
}
bool CCountedStringPool::RestoreFromBuffer( CUtlBuffer &buffer )
{
int signature = buffer.GetInt();
if ( signature != STRING_POOL_VERSION )
{
// wrong version
return false;
}
FreeAll();
m_FreeListStart = buffer.GetUnsignedShort();
int hashCount = buffer.GetInt();
m_HashTable.SetCount( hashCount );
for ( int i = 0; i < hashCount; i++ )
{
m_HashTable[i] = buffer.GetUnsignedShort();
}
int tableCount = buffer.GetInt();
if ( tableCount > 1 )
{
m_Elements.AddMultipleToTail( tableCount-1 );
}
char tempString[MAX_STRING_SAVE];
for ( int i = 1; i < tableCount; i++ )
{
m_Elements[i].nNextElement = buffer.GetUnsignedShort();
m_Elements[i].nReferenceCount = buffer.GetUnsignedChar();
buffer.GetString( tempString, sizeof( tempString ) );
m_Elements[i].pString = strdup( tempString );
}
return buffer.IsValid();
}
+2632
View File
File diff suppressed because it is too large Load Diff
+29
View 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();
}
+1795
View File
File diff suppressed because it is too large Load Diff
+554
View File
@@ -0,0 +1,554 @@
//====== Copyright 1996-2004, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "tier1/utlstring.h"
#include "tier1/strtools.h"
#include <ctype.h>
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Base class, containing simple memory management
//-----------------------------------------------------------------------------
CUtlBinaryBlock::CUtlBinaryBlock( int growSize, int initSize )
{
MEM_ALLOC_CREDIT();
m_Memory.Init( growSize, initSize );
m_nActualLength = 0;
}
CUtlBinaryBlock::CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Memory( (unsigned char*)pMemory, nSizeInBytes )
{
m_nActualLength = nInitialLength;
}
CUtlBinaryBlock::CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ) : m_Memory( (const unsigned char*)pMemory, nSizeInBytes )
{
m_nActualLength = nSizeInBytes;
}
CUtlBinaryBlock::CUtlBinaryBlock( const CUtlBinaryBlock& src )
{
Set( src.Get(), src.Length() );
}
void CUtlBinaryBlock::Get( void *pValue, int nLen ) const
{
Assert( nLen > 0 );
if ( m_nActualLength < nLen )
{
nLen = m_nActualLength;
}
if ( nLen > 0 )
{
memcpy( pValue, m_Memory.Base(), nLen );
}
}
void CUtlBinaryBlock::SetLength( int nLength )
{
MEM_ALLOC_CREDIT();
Assert( !m_Memory.IsReadOnly() );
m_nActualLength = nLength;
if ( nLength > m_Memory.NumAllocated() )
{
int nOverFlow = nLength - m_Memory.NumAllocated();
m_Memory.Grow( nOverFlow );
// If the reallocation failed, clamp length
if ( nLength > m_Memory.NumAllocated() )
{
m_nActualLength = m_Memory.NumAllocated();
}
}
#ifdef _DEBUG
if ( m_Memory.NumAllocated() > m_nActualLength )
{
memset( ( ( char * )m_Memory.Base() ) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength );
}
#endif
}
void CUtlBinaryBlock::Set( const void *pValue, int nLen )
{
Assert( !m_Memory.IsReadOnly() );
if ( !pValue )
{
nLen = 0;
}
SetLength( nLen );
if ( m_nActualLength )
{
if ( ( ( const char * )m_Memory.Base() ) >= ( ( const char * )pValue ) + nLen ||
( ( const char * )m_Memory.Base() ) + m_nActualLength <= ( ( const char * )pValue ) )
{
memcpy( m_Memory.Base(), pValue, m_nActualLength );
}
else
{
memmove( m_Memory.Base(), pValue, m_nActualLength );
}
}
}
CUtlBinaryBlock &CUtlBinaryBlock::operator=( const CUtlBinaryBlock &src )
{
Assert( !m_Memory.IsReadOnly() );
Set( src.Get(), src.Length() );
return *this;
}
bool CUtlBinaryBlock::operator==( const CUtlBinaryBlock &src ) const
{
if ( src.Length() != Length() )
return false;
return !memcmp( src.Get(), Get(), Length() );
}
//-----------------------------------------------------------------------------
// Simple string class.
//-----------------------------------------------------------------------------
CUtlString::CUtlString()
{
}
CUtlString::CUtlString( const char *pString )
{
Set( pString );
}
CUtlString::CUtlString( const CUtlString& string )
{
Set( string.Get() );
}
// Attaches the string to external memory. Useful for avoiding a copy
CUtlString::CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength ) : m_Storage( pMemory, nSizeInBytes, nInitialLength )
{
}
CUtlString::CUtlString( const void* pMemory, int nSizeInBytes ) : m_Storage( pMemory, nSizeInBytes )
{
}
//-----------------------------------------------------------------------------
// Purpose: Set directly and don't look for a null terminator in pValue.
//-----------------------------------------------------------------------------
void CUtlString::SetDirect( const char *pValue, int nChars )
{
if ( nChars > 0 )
{
m_Storage.SetLength( nChars+1 );
m_Storage.Set( pValue, nChars );
m_Storage[nChars] = 0;
}
else
{
m_Storage.SetLength( 0 );
}
}
void CUtlString::Set( const char *pValue )
{
Assert( !m_Storage.IsReadOnly() );
int nLen = pValue ? V_strlen(pValue) + 1 : 0;
m_Storage.Set( pValue, nLen );
}
// Returns strlen
int CUtlString::Length() const
{
return m_Storage.Length() ? m_Storage.Length() - 1 : 0;
}
// Sets the length (used to serialize into the buffer )
void CUtlString::SetLength( int nLen )
{
Assert( !m_Storage.IsReadOnly() );
// Add 1 to account for the NULL
m_Storage.SetLength( nLen > 0 ? nLen + 1 : 0 );
}
const char *CUtlString::Get( ) const
{
if ( m_Storage.Length() == 0 )
{
return "";
}
return reinterpret_cast< const char* >( m_Storage.Get() );
}
// Converts to c-strings
CUtlString::operator const char*() const
{
return Get();
}
char *CUtlString::Get()
{
Assert( !m_Storage.IsReadOnly() );
if ( m_Storage.Length() == 0 )
{
// In general, we optimise away small mallocs for empty strings
// but if you ask for the non-const bytes, they must be writable
// so we can't return "" here, like we do for the const version - jd
m_Storage.SetLength( 1 );
m_Storage[ 0 ] = '\0';
}
return reinterpret_cast< char* >( m_Storage.Get() );
}
void CUtlString::Purge()
{
m_Storage.Purge();
}
void CUtlString::ToLower()
{
for( int nLength = Length() - 1; nLength >= 0; nLength-- )
{
m_Storage[ nLength ] = tolower( m_Storage[ nLength ] );
}
}
CUtlString &CUtlString::operator=( const CUtlString &src )
{
Assert( !m_Storage.IsReadOnly() );
m_Storage = src.m_Storage;
return *this;
}
CUtlString &CUtlString::operator=( const char *src )
{
Assert( !m_Storage.IsReadOnly() );
Set( src );
return *this;
}
bool CUtlString::operator==( const CUtlString &src ) const
{
return m_Storage == src.m_Storage;
}
bool CUtlString::operator==( const char *src ) const
{
return ( strcmp( Get(), src ) == 0 );
}
CUtlString &CUtlString::operator+=( const CUtlString &rhs )
{
Assert( !m_Storage.IsReadOnly() );
const int lhsLength( Length() );
const int rhsLength( rhs.Length() );
const int requestedLength( lhsLength + rhsLength );
SetLength( requestedLength );
const int allocatedLength( Length() );
const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
memcpy( Get() + lhsLength, rhs.Get(), copyLength );
m_Storage[ allocatedLength ] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=( const char *rhs )
{
Assert( !m_Storage.IsReadOnly() );
const int lhsLength( Length() );
const int rhsLength( V_strlen( rhs ) );
const int requestedLength( lhsLength + rhsLength );
SetLength( requestedLength );
const int allocatedLength( Length() );
const int copyLength( allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength );
memcpy( Get() + lhsLength, rhs, copyLength );
m_Storage[ allocatedLength ] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=( char c )
{
Assert( !m_Storage.IsReadOnly() );
int nLength = Length();
SetLength( nLength + 1 );
m_Storage[ nLength ] = c;
m_Storage[ nLength+1 ] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=( int rhs )
{
Assert( !m_Storage.IsReadOnly() );
Assert( sizeof( rhs ) == 4 );
char tmpBuf[ 12 ]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ]
V_snprintf( tmpBuf, sizeof( tmpBuf ), "%d", rhs );
tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
return operator+=( tmpBuf );
}
CUtlString &CUtlString::operator+=( double rhs )
{
Assert( !m_Storage.IsReadOnly() );
char tmpBuf[ 256 ]; // How big can doubles be??? Dunno.
V_snprintf( tmpBuf, sizeof( tmpBuf ), "%lg", rhs );
tmpBuf[ sizeof( tmpBuf ) - 1 ] = '\0';
return operator+=( tmpBuf );
}
bool CUtlString::MatchesPattern( const CUtlString &Pattern, int nFlags ) const
{
const char *pszSource = String();
const char *pszPattern = Pattern.String();
bool bExact = true;
while( 1 )
{
if ( ( *pszPattern ) == 0 )
{
return ( (*pszSource ) == 0 );
}
if ( ( *pszPattern ) == '*' )
{
pszPattern++;
if ( ( *pszPattern ) == 0 )
{
return true;
}
bExact = false;
continue;
}
int nLength = 0;
while( ( *pszPattern ) != '*' && ( *pszPattern ) != 0 )
{
nLength++;
pszPattern++;
}
while( 1 )
{
const char *pszStartPattern = pszPattern - nLength;
const char *pszSearch = pszSource;
for( int i = 0; i < nLength; i++, pszSearch++, pszStartPattern++ )
{
if ( ( *pszSearch ) == 0 )
{
return false;
}
if ( ( *pszSearch ) != ( *pszStartPattern ) )
{
break;
}
}
if ( pszSearch - pszSource == nLength )
{
break;
}
if ( bExact == true )
{
return false;
}
if ( ( nFlags & PATTERN_DIRECTORY ) != 0 )
{
if ( ( *pszPattern ) != '/' && ( *pszSource ) == '/' )
{
return false;
}
}
pszSource++;
}
pszSource += nLength;
}
}
int CUtlString::Format( const char *pFormat, ... )
{
Assert( !m_Storage.IsReadOnly() );
char tmpBuf[ 4096 ]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer
va_list marker;
va_start( marker, pFormat );
#ifdef _WIN32
int len = _vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
#elif POSIX
int len = vsnprintf( tmpBuf, sizeof( tmpBuf ) - 1, pFormat, marker );
#else
#error "define vsnprintf type."
#endif
va_end( marker );
// Len > maxLen represents an overflow on POSIX, < 0 is an overflow on windows
if( len < 0 || len >= sizeof( tmpBuf ) - 1 )
{
len = sizeof( tmpBuf ) - 1;
tmpBuf[sizeof( tmpBuf ) - 1] = 0;
}
Set( tmpBuf );
return len;
}
//-----------------------------------------------------------------------------
// Strips the trailing slash
//-----------------------------------------------------------------------------
void CUtlString::StripTrailingSlash()
{
if ( IsEmpty() )
return;
int nLastChar = Length() - 1;
char c = m_Storage[ nLastChar ];
if ( c == '\\' || c == '/' )
{
m_Storage[ nLastChar ] = 0;
m_Storage.SetLength( m_Storage.Length() - 1 );
}
}
CUtlString CUtlString::Slice( int32 nStart, int32 nEnd ) const
{
if ( nStart < 0 )
nStart = Length() - (-nStart % Length());
else if ( nStart >= Length() )
nStart = Length();
if ( nEnd == INT32_MAX )
nEnd = Length();
else if ( nEnd < 0 )
nEnd = Length() - (-nEnd % Length());
else if ( nEnd >= Length() )
nEnd = Length();
if ( nStart >= nEnd )
return CUtlString( "" );
const char *pIn = String();
CUtlString ret;
ret.m_Storage.SetLength( nEnd - nStart + 1 );
char *pOut = (char*)ret.m_Storage.Get();
memcpy( ret.m_Storage.Get(), &pIn[nStart], nEnd - nStart );
pOut[nEnd - nStart] = 0;
return ret;
}
// Grab a substring starting from the left or the right side.
CUtlString CUtlString::Left( int32 nChars ) const
{
return Slice( 0, nChars );
}
CUtlString CUtlString::Right( int32 nChars ) const
{
return Slice( -nChars );
}
CUtlString CUtlString::Replace( char cFrom, char cTo ) const
{
CUtlString ret = *this;
int len = ret.Length();
for ( int i=0; i < len; i++ )
{
if ( ret.m_Storage[i] == cFrom )
ret.m_Storage[i] = cTo;
}
return ret;
}
CUtlString CUtlString::AbsPath( const char *pStartingDir ) const
{
char szNew[MAX_PATH];
V_MakeAbsolutePath( szNew, sizeof( szNew ), this->String(), pStartingDir );
return CUtlString( szNew );
}
CUtlString CUtlString::UnqualifiedFilename() const
{
const char *pFilename = V_UnqualifiedFileName( this->String() );
return CUtlString( pFilename );
}
CUtlString CUtlString::DirName() const
{
CUtlString ret( this->String() );
V_StripLastDir( (char*)ret.m_Storage.Get(), ret.m_Storage.Length() );
V_StripTrailingSlash( (char*)ret.m_Storage.Get() );
return ret;
}
CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 )
{
char szPath[MAX_PATH];
V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) );
return CUtlString( szPath );
}
CUtlString CUtlString::operator+( const char *pOther ) const
{
CUtlString s = *this;
s += pOther;
return s;
}
//-----------------------------------------------------------------------------
// Purpose: concatenate the provided string to our current content
//-----------------------------------------------------------------------------
void CUtlString::Append( const char *pchAddition )
{
CUtlString s = *this;
s += pchAddition;
}
+513
View File
@@ -0,0 +1,513 @@
//========= Copyright 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 false;
if ( !str2 && str1 )
return true;
if ( !str1 && !str2 )
return false;
// 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 false;
if ( !str2 && str1 )
return true;
if ( !str1 && !str2 )
return false;
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 ];
V_strncpy( fn, pFileName, sizeof( fn ) );
V_RemoveDotSlashes( fn );
// Split the filename into constituent parts
char basepath[ MAX_PATH ];
V_ExtractFilePath( fn, basepath, sizeof( basepath ) );
char filename[ MAX_PATH ];
V_strncpy( filename, fn + V_strlen( basepath ), sizeof( filename ) );
// not found, lock and look again
FileNameHandleInternal_t handle;
m_lock.LockForWrite();
handle.path = m_StringPool.FindStringHandle( basepath );
handle.file = m_StringPool.FindStringHandle( filename );
if ( handle.path && handle.file )
{
// found
m_lock.UnlockWrite();
return *( FileNameHandle_t * )( &handle );
}
// safely add it
handle.path = m_StringPool.ReferenceStringHandle( basepath );
handle.file = m_StringPool.ReferenceStringHandle( filename );
m_lock.UnlockWrite();
return *( FileNameHandle_t * )( &handle );
}
FileNameHandle_t CUtlFilenameSymbolTable::FindFileName( const char *pFileName )
{
if ( !pFileName )
{
return NULL;
}
// Fix slashes+dotslashes and make lower case first..
char fn[ MAX_PATH ];
V_strncpy( fn, pFileName, sizeof( fn ) );
V_RemoveDotSlashes( fn );
// Split the filename into constituent parts
char basepath[ MAX_PATH ];
V_ExtractFilePath( fn, basepath, sizeof( basepath ) );
char filename[ MAX_PATH ];
V_strncpy( filename, fn + V_strlen( basepath ), sizeof( filename ) );
FileNameHandleInternal_t handle;
m_lock.LockForRead();
handle.path = m_StringPool.FindStringHandle(basepath);
handle.file = m_StringPool.FindStringHandle(filename);
m_lock.UnlockRead();
if ( ( handle.path == 0 ) || ( handle.file == 0 ) )
return NULL;
return *( FileNameHandle_t * )( &handle );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : handle -
// Output : const char
//-----------------------------------------------------------------------------
bool CUtlFilenameSymbolTable::String( const FileNameHandle_t& handle, char *buf, int buflen )
{
buf[ 0 ] = 0;
FileNameHandleInternal_t *internal = ( FileNameHandleInternal_t * )&handle;
if ( !internal )
{
return false;
}
m_lock.LockForRead();
const char *path = m_StringPool.HandleToString(internal->path);
const char *fn = m_StringPool.HandleToString(internal->file);
m_lock.UnlockRead();
if ( !path || !fn )
{
return false;
}
V_strncpy( buf, path, buflen );
V_strncat( buf, fn, buflen, COPY_ALL_CHARACTERS );
return true;
}
void CUtlFilenameSymbolTable::RemoveAll()
{
m_StringPool.FreeAll();
}
void CUtlFilenameSymbolTable::SpewStrings()
{
m_lock.LockForRead();
m_StringPool.SpewStrings();
m_lock.UnlockRead();
}
bool CUtlFilenameSymbolTable::SaveToBuffer( CUtlBuffer &buffer )
{
m_lock.LockForRead();
bool bResult = m_StringPool.SaveToBuffer( buffer );
m_lock.UnlockRead();
return bResult;
}
bool CUtlFilenameSymbolTable::RestoreFromBuffer( CUtlBuffer &buffer )
{
m_lock.LockForWrite();
bool bResult = m_StringPool.RestoreFromBuffer( buffer );
m_lock.UnlockWrite();
return bResult;
}