openDecal/Native/DecalNet/MessageLoaders.cpp
erik d1442e3747 Initial commit: Complete open-source Decal rebuild
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>
2026-02-08 18:27:56 +01:00

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;