diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tier1/kvpacker.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'tier1/kvpacker.cpp')
| -rw-r--r-- | tier1/kvpacker.cpp | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/tier1/kvpacker.cpp b/tier1/kvpacker.cpp new file mode 100644 index 0000000..53f7672 --- /dev/null +++ b/tier1/kvpacker.cpp @@ -0,0 +1,285 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Contains a branch-neutral binary packer for KeyValues trees. +// +// $NoKeywords: $ +// +//=============================================================================// + +#include <KeyValues.h> +#include "kvpacker.h" + +#include "tier0/dbg.h" +#include "utlbuffer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + +#define KEYVALUES_TOKEN_SIZE 1024 + +// writes KeyValue as binary data to buffer +bool KVPacker::WriteAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) +{ + if ( buffer.IsText() ) // must be a binary buffer + return false; + + if ( !buffer.IsValid() ) // must be valid, no overflows etc + return false; + + // Write subkeys: + + // loop through all our peers + for ( KeyValues *dat = pNode; dat != NULL; dat = dat->GetNextKey() ) + { + // write type + switch ( dat->GetDataType() ) + { + case KeyValues::TYPE_NONE: + { + buffer.PutUnsignedChar( PACKTYPE_NONE ); + break; + } + case KeyValues::TYPE_STRING: + { + buffer.PutUnsignedChar( PACKTYPE_STRING ); + break; + } + case KeyValues::TYPE_WSTRING: + { + buffer.PutUnsignedChar( PACKTYPE_WSTRING ); + break; + } + + case KeyValues::TYPE_INT: + { + buffer.PutUnsignedChar( PACKTYPE_INT ); + break; + } + + case KeyValues::TYPE_UINT64: + { + buffer.PutUnsignedChar( PACKTYPE_UINT64 ); + break; + } + + case KeyValues::TYPE_FLOAT: + { + buffer.PutUnsignedChar( PACKTYPE_FLOAT ); + break; + } + case KeyValues::TYPE_COLOR: + { + buffer.PutUnsignedChar( PACKTYPE_COLOR ); + break; + } + case KeyValues::TYPE_PTR: + { + buffer.PutUnsignedChar( PACKTYPE_PTR ); + break; + } + + default: + break; + } + + // write name + buffer.PutString( dat->GetName() ); + + // write value + switch ( dat->GetDataType() ) + { + case KeyValues::TYPE_NONE: + { + if( !WriteAsBinary( dat->GetFirstSubKey(), buffer ) ) + return false; + break; + } + case KeyValues::TYPE_STRING: + { + if (dat->GetString() && *(dat->GetString())) + { + buffer.PutString( dat->GetString() ); + } + else + { + buffer.PutString( "" ); + } + break; + } + case KeyValues::TYPE_WSTRING: + { + int nLength = dat->GetWString() ? Q_wcslen( dat->GetWString() ) : 0; + buffer.PutShort( nLength ); + for( int k = 0; k < nLength; ++ k ) + { + buffer.PutShort( ( unsigned short ) dat->GetWString()[k] ); + } + break; + } + + case KeyValues::TYPE_INT: + { + buffer.PutInt( dat->GetInt() ); + break; + } + + case KeyValues::TYPE_UINT64: + { + buffer.PutInt64( dat->GetUint64() ); + break; + } + + case KeyValues::TYPE_FLOAT: + { + buffer.PutFloat( dat->GetFloat() ); + break; + } + case KeyValues::TYPE_COLOR: + { + Color color = dat->GetColor(); + buffer.PutUnsignedChar( color[0] ); + buffer.PutUnsignedChar( color[1] ); + buffer.PutUnsignedChar( color[2] ); + buffer.PutUnsignedChar( color[3] ); + break; + } + case KeyValues::TYPE_PTR: + { + buffer.PutUnsignedInt( (int)dat->GetPtr() ); + break; + } + + default: + break; + } + } + + // write tail, marks end of peers + buffer.PutUnsignedChar( PACKTYPE_NULLMARKER ); + + return buffer.IsValid(); +} + +// read KeyValues from binary buffer, returns true if parsing was successful +bool KVPacker::ReadAsBinary( KeyValues *pNode, CUtlBuffer &buffer ) +{ + if ( buffer.IsText() ) // must be a binary buffer + return false; + + if ( !buffer.IsValid() ) // must be valid, no overflows etc + return false; + + pNode->Clear(); + + char token[KEYVALUES_TOKEN_SIZE]; + KeyValues *dat = pNode; + EPackType ePackType = (EPackType)buffer.GetUnsignedChar(); + + // loop through all our peers + while ( true ) + { + if ( ePackType == PACKTYPE_NULLMARKER ) + break; // no more peers + + buffer.GetString( token ); + 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, (void*)buffer.GetUnsignedInt() ); + break; + } + + default: + break; + } + + if ( !buffer.IsValid() ) // error occured + return false; + + ePackType = (EPackType)buffer.GetUnsignedChar(); + + if ( ePackType == PACKTYPE_NULLMARKER ) + break; + + // new peer follows + KeyValues *pNewPeer = new KeyValues(""); + dat->SetNextKey( pNewPeer ); + dat = pNewPeer; + } + + return buffer.IsValid(); +} + |