All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
207 lines
4.8 KiB
C++
207 lines
4.8 KiB
C++
// MessageLoaders.cpp
|
|
// Implementation of message loaders for various data types
|
|
|
|
#include "StdAfx.h"
|
|
#include "MessageLoaders.h"
|
|
|
|
// The boatload of decoding classes
|
|
template< class ValueT >
|
|
class cVariantLoader
|
|
: public cFieldLoader
|
|
{
|
|
public:
|
|
virtual void *skip( void *pData )
|
|
{
|
|
return reinterpret_cast< BYTE * >( pData ) + sizeof( ValueT );
|
|
}
|
|
|
|
virtual void *align( void *pData, void *pStart )
|
|
{
|
|
size_t nOffset = reinterpret_cast< BYTE * >( pData ) - reinterpret_cast< BYTE * >( pStart );
|
|
if( ( nOffset % sizeof( ValueT ) ) == 0 )
|
|
return pData;
|
|
|
|
return ( reinterpret_cast< BYTE * >( pStart ) + nOffset + sizeof( ValueT ) - ( nOffset % sizeof( ValueT ) ) );
|
|
}
|
|
|
|
virtual bool testValue( void *pData, void *pEnd )
|
|
{
|
|
return ( ( reinterpret_cast< BYTE * >( pData ) + sizeof( ValueT ) ) <= reinterpret_cast< BYTE * >( pEnd ) );
|
|
}
|
|
|
|
ValueT &valueOf( void *pvData )
|
|
{
|
|
return *reinterpret_cast< ValueT * >( pvData );
|
|
}
|
|
};
|
|
|
|
class cByteLoader
|
|
: public cVariantLoader< BYTE >
|
|
{
|
|
public:
|
|
virtual void getValue( void *pvData, LPVARIANT pDest )
|
|
{
|
|
pDest->vt = VT_UI1;
|
|
pDest->bVal = valueOf( pvData );
|
|
}
|
|
|
|
virtual long getNumber( void *pvData )
|
|
{
|
|
return valueOf( pvData );
|
|
}
|
|
};
|
|
|
|
class cShortLoader
|
|
: public cVariantLoader< short >
|
|
{
|
|
public:
|
|
virtual void getValue( void *pvData, LPVARIANT pDest )
|
|
{
|
|
pDest->vt = VT_I2;
|
|
pDest->iVal = valueOf( pvData );
|
|
}
|
|
|
|
virtual long getNumber( void *pvData )
|
|
{
|
|
return valueOf( pvData );
|
|
}
|
|
};
|
|
|
|
class cLongLoader
|
|
: public cVariantLoader< long >
|
|
{
|
|
public:
|
|
virtual void getValue( void *pvData, LPVARIANT pDest )
|
|
{
|
|
pDest->vt = VT_I4;
|
|
pDest->lVal = valueOf( pvData );
|
|
}
|
|
|
|
virtual long getNumber( void *pvData )
|
|
{
|
|
return valueOf( pvData );
|
|
}
|
|
};
|
|
|
|
class cFloatLoader
|
|
: public cVariantLoader< float >
|
|
{
|
|
public:
|
|
virtual void getValue( void *pvData, LPVARIANT pDest )
|
|
{
|
|
pDest->vt = VT_R4;
|
|
pDest->fltVal = valueOf( pvData );
|
|
}
|
|
};
|
|
|
|
class cDoubleLoader
|
|
: public cVariantLoader< double >
|
|
{
|
|
public:
|
|
virtual void getValue( void *pvData, LPVARIANT pDest )
|
|
{
|
|
pDest->vt = VT_R8;
|
|
pDest->dblVal = valueOf( pvData );
|
|
}
|
|
};
|
|
|
|
class cStringLoader
|
|
: public cFieldLoader
|
|
{
|
|
public:
|
|
virtual void *skip( void *pvData )
|
|
{
|
|
WORD wLength = *reinterpret_cast< WORD * >( pvData ) + sizeof( WORD );
|
|
if( ( wLength % sizeof( DWORD ) ) != 0 )
|
|
wLength += sizeof( DWORD ) - ( wLength % sizeof( DWORD ) );
|
|
|
|
return reinterpret_cast< BYTE * >( pvData ) + wLength;
|
|
}
|
|
|
|
virtual void *align( void *pvData, void * )
|
|
{
|
|
// Error, this is not a valid alignment type
|
|
_ASSERTE( FALSE );
|
|
|
|
return pvData;
|
|
}
|
|
|
|
virtual bool testValue( void *pvData, void *pvEnd )
|
|
{
|
|
WORD wLength = *reinterpret_cast< WORD * >( pvData ) + sizeof( WORD ),
|
|
wField = wLength;
|
|
|
|
if( ( wField % sizeof( DWORD ) ) != 0 )
|
|
wField += sizeof( DWORD ) - ( wField % sizeof( DWORD ) );
|
|
|
|
// It fits inside the packet, so our field isn't too big
|
|
if( ( reinterpret_cast< BYTE * >( pvData ) + wField ) > reinterpret_cast< BYTE * >( pvEnd ) )
|
|
return false;
|
|
|
|
// Strings are no longer NULL-Terminated in the stream
|
|
//if( *( reinterpret_cast< char * >( pvData ) + wLength - 1 ) != '\0' )
|
|
// This string is not NULL terminated
|
|
// return false;
|
|
|
|
// Anything else just makes the string ugly, but won't lead to a memory
|
|
// overrun, so let them play
|
|
return true;
|
|
}
|
|
|
|
virtual void getValue( void *pvData, LPVARIANT pDest )
|
|
{
|
|
pDest->vt = VT_BSTR;
|
|
|
|
USES_CONVERSION;
|
|
WORD wLength = *(WORD *) pvData;
|
|
|
|
// make new string
|
|
char *szString = new char[wLength + 1];
|
|
szString[wLength] = 0;
|
|
|
|
memcpy( szString, (((BYTE*) pvData) + sizeof( WORD )), wLength );
|
|
|
|
pDest->bstrVal = A2BSTR( szString );
|
|
|
|
delete [] szString;
|
|
}
|
|
};
|
|
|
|
long cFieldLoader::getNumber( void *pvData )
|
|
{
|
|
// This default implementation does not support this conversion
|
|
_ASSERTE( FALSE );
|
|
|
|
return 0;
|
|
}
|
|
|
|
cFieldLoader *cFieldLoader::lookup( const _bstr_t &strName )
|
|
{
|
|
cFieldLoaderMap::iterator i = g_primitives.find( strName );
|
|
if( i == g_primitives.end() )
|
|
return NULL;
|
|
|
|
return i->second.get();
|
|
}
|
|
|
|
void cFieldLoader::init()
|
|
{
|
|
addLoader( _T( "BYTE" ), new cByteLoader );
|
|
addLoader( _T( "WORD" ), new cShortLoader );
|
|
addLoader( _T( "DWORD" ), new cLongLoader );
|
|
addLoader( _T( "float" ), new cFloatLoader );
|
|
addLoader( _T( "double" ), new cDoubleLoader );
|
|
addLoader( _T( "String" ), new cStringLoader );
|
|
}
|
|
|
|
void cFieldLoader::term()
|
|
{
|
|
g_primitives.clear();
|
|
}
|
|
|
|
void cFieldLoader::addLoader( LPCTSTR szName, cFieldLoader *pLoader )
|
|
{
|
|
g_primitives.insert( cFieldLoaderMap::value_type( szName, VSBridge::auto_ptr< cFieldLoader >( pLoader ) ) );
|
|
}
|
|
|
|
cFieldLoader::cFieldLoaderMap cFieldLoader::g_primitives;
|