// 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; 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 ) { USES_CONVERSION; pDest->vt = VT_BSTR; pDest->bstrVal = A2BSTR( reinterpret_cast< char * >( reinterpret_cast< BYTE * >( pvData ) + sizeof( WORD ) ) ); } }; 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, std::auto_ptr< cFieldLoader >( pLoader ) ) ); } cFieldLoader::cFieldLoaderMap cFieldLoader::g_primitives;