You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
5.6 KiB
285 lines
5.6 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Contains a branch-neutral binary packer for KeyValues trees. |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
|
|
#include <KeyValues.h> |
|
#include "kvpacker.h" |
|
|
|
#include "tier0/dbg.h" |
|
#include "utlbuffer.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
#define KEYVALUES_TOKEN_SIZE 1024 |
|
|
|
// writes KeyValue as binary data to buffer |
|
bool KVPacker::WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) |
|
{ |
|
if ( buffer.IsText() ) // must be a binary buffer |
|
return false; |
|
|
|
if ( !buffer.IsValid() ) // must be valid, no overflows etc |
|
return false; |
|
|
|
// Write subkeys: |
|
|
|
// loop through all our peers |
|
for ( KeyValues *dat = pNode; dat != NULL; dat = dat->GetNextKey() ) |
|
{ |
|
// write type |
|
switch ( dat->GetDataType() ) |
|
{ |
|
case KeyValues::TYPE_NONE: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_NONE ); |
|
break; |
|
} |
|
case KeyValues::TYPE_STRING: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_STRING ); |
|
break; |
|
} |
|
case KeyValues::TYPE_WSTRING: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_WSTRING ); |
|
break; |
|
} |
|
|
|
case KeyValues::TYPE_INT: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_INT ); |
|
break; |
|
} |
|
|
|
case KeyValues::TYPE_UINT64: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_UINT64 ); |
|
break; |
|
} |
|
|
|
case KeyValues::TYPE_FLOAT: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_FLOAT ); |
|
break; |
|
} |
|
case KeyValues::TYPE_COLOR: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_COLOR ); |
|
break; |
|
} |
|
case KeyValues::TYPE_PTR: |
|
{ |
|
buffer.PutUnsignedChar( PACKTYPE_PTR ); |
|
break; |
|
} |
|
|
|
default: |
|
break; |
|
} |
|
|
|
// write name |
|
buffer.PutString( dat->GetName() ); |
|
|
|
// write value |
|
switch ( dat->GetDataType() ) |
|
{ |
|
case KeyValues::TYPE_NONE: |
|
{ |
|
if( !WriteAsBinary( dat->GetFirstSubKey(), buffer ) ) |
|
return false; |
|
break; |
|
} |
|
case KeyValues::TYPE_STRING: |
|
{ |
|
if (dat->GetString() && *(dat->GetString())) |
|
{ |
|
buffer.PutString( dat->GetString() ); |
|
} |
|
else |
|
{ |
|
buffer.PutString( "" ); |
|
} |
|
break; |
|
} |
|
case KeyValues::TYPE_WSTRING: |
|
{ |
|
int nLength = dat->GetWString() ? Q_wcslen( dat->GetWString() ) : 0; |
|
buffer.PutShort( nLength ); |
|
for( int k = 0; k < nLength; ++ k ) |
|
{ |
|
buffer.PutShort( ( unsigned short ) dat->GetWString()[k] ); |
|
} |
|
break; |
|
} |
|
|
|
case KeyValues::TYPE_INT: |
|
{ |
|
buffer.PutInt( dat->GetInt() ); |
|
break; |
|
} |
|
|
|
case KeyValues::TYPE_UINT64: |
|
{ |
|
buffer.PutInt64( dat->GetUint64() ); |
|
break; |
|
} |
|
|
|
case KeyValues::TYPE_FLOAT: |
|
{ |
|
buffer.PutFloat( dat->GetFloat() ); |
|
break; |
|
} |
|
case KeyValues::TYPE_COLOR: |
|
{ |
|
Color color = dat->GetColor(); |
|
buffer.PutUnsignedChar( color[0] ); |
|
buffer.PutUnsignedChar( color[1] ); |
|
buffer.PutUnsignedChar( color[2] ); |
|
buffer.PutUnsignedChar( color[3] ); |
|
break; |
|
} |
|
case KeyValues::TYPE_PTR: |
|
{ |
|
buffer.PutUnsignedInt( (uintptr_t)dat->GetPtr() ); |
|
break; |
|
} |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
// write tail, marks end of peers |
|
buffer.PutUnsignedChar( PACKTYPE_NULLMARKER ); |
|
|
|
return buffer.IsValid(); |
|
} |
|
|
|
// read KeyValues from binary buffer, returns true if parsing was successful |
|
bool KVPacker::ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) |
|
{ |
|
if ( buffer.IsText() ) // must be a binary buffer |
|
return false; |
|
|
|
if ( !buffer.IsValid() ) // must be valid, no overflows etc |
|
return false; |
|
|
|
pNode->Clear(); |
|
|
|
char token[KEYVALUES_TOKEN_SIZE]; |
|
KeyValues *dat = pNode; |
|
EPackType ePackType = (EPackType)buffer.GetUnsignedChar(); |
|
|
|
// loop through all our peers |
|
while ( true ) |
|
{ |
|
if ( ePackType == PACKTYPE_NULLMARKER ) |
|
break; // no more peers |
|
|
|
buffer.GetString( token ); |
|
token[KEYVALUES_TOKEN_SIZE-1] = 0; |
|
|
|
dat->SetName( token ); |
|
|
|
switch ( ePackType ) |
|
{ |
|
case PACKTYPE_NONE: |
|
{ |
|
KeyValues *pNewNode = new KeyValues(""); |
|
dat->AddSubKey( pNewNode ); |
|
if( !ReadAsBinary( pNewNode, buffer ) ) |
|
return false; |
|
break; |
|
} |
|
case PACKTYPE_STRING: |
|
{ |
|
buffer.GetString( token ); |
|
token[KEYVALUES_TOKEN_SIZE-1] = 0; |
|
dat->SetStringValue( token ); |
|
break; |
|
} |
|
case PACKTYPE_WSTRING: |
|
{ |
|
int nLength = buffer.GetShort(); |
|
if ( nLength >= 0 && nLength*sizeof( uint16 ) <= (uint)buffer.GetBytesRemaining() ) |
|
{ |
|
if ( nLength > 0 ) |
|
{ |
|
wchar_t *pTemp = (wchar_t *)malloc( sizeof( wchar_t ) * (1 + nLength) ); |
|
|
|
for ( int k = 0; k < nLength; ++k ) |
|
{ |
|
pTemp[k] = buffer.GetShort(); // ugly, but preserving existing behavior |
|
} |
|
|
|
pTemp[nLength] = 0; |
|
dat->SetWString( NULL, pTemp ); |
|
|
|
free( pTemp ); |
|
} |
|
else |
|
dat->SetWString( NULL, L"" ); |
|
|
|
} |
|
break; |
|
} |
|
|
|
case PACKTYPE_INT: |
|
{ |
|
dat->SetInt( NULL, buffer.GetInt() ); |
|
break; |
|
} |
|
|
|
case PACKTYPE_UINT64: |
|
{ |
|
dat->SetUint64( NULL, (uint64)buffer.GetInt64() ); |
|
break; |
|
} |
|
|
|
case PACKTYPE_FLOAT: |
|
{ |
|
dat->SetFloat( NULL, buffer.GetFloat() ); |
|
break; |
|
} |
|
case PACKTYPE_COLOR: |
|
{ |
|
Color color( |
|
buffer.GetUnsignedChar(), |
|
buffer.GetUnsignedChar(), |
|
buffer.GetUnsignedChar(), |
|
buffer.GetUnsignedChar() ); |
|
dat->SetColor( NULL, color ); |
|
break; |
|
} |
|
case PACKTYPE_PTR: |
|
{ |
|
dat->SetPtr( NULL, buffer.GetPtr() ); |
|
break; |
|
} |
|
|
|
default: |
|
break; |
|
} |
|
|
|
if ( !buffer.IsValid() ) // error occured |
|
return false; |
|
|
|
ePackType = (EPackType)buffer.GetUnsignedChar(); |
|
|
|
if ( ePackType == PACKTYPE_NULLMARKER ) |
|
break; |
|
|
|
// new peer follows |
|
KeyValues *pNewPeer = new KeyValues(""); |
|
dat->SetNextKey( pNewPeer ); |
|
dat = pNewPeer; |
|
} |
|
|
|
return buffer.IsValid(); |
|
} |
|
|
|
|