openDecal/Native/Inject/Attic/MessageParsers-Cibo.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

701 lines
20 KiB
C++

// MessageParsers.cpp
// Implementation of parsers and runtime objects for parsing message data
#include "StdAfx.h"
#include "Inject.h"
#include "MessageParsers.h"
#include "MessageLoaders.h"
#include "MessageStruct.h"
#include "MessageVector.h"
class cStructElement
: public cMessage::cMessageElement
{
public:
cMessage::cElementList m_members;
virtual bool load( cMessage::cLoadContext &context )
{
// Walk through the list of members and have them load
int nIndex = context.addField( this, NULL );
for( cMessage::cElementList::iterator i = m_members.begin(); i != m_members.end(); ++ i )
{
if( !i->get()->load( cMessage::cLoadContext( &context ) ) )
return false;
}
// Update the field count
context.groupField( nIndex );
return true;
}
virtual void getValue( cMessage *pMessage, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
if( i->m_pDisp.p == NULL )
{
// Create the vector object
CComObject< cMessageStruct > *pVecDisp;
CComObject< cMessageStruct >::CreateInstance( &pVecDisp );
pVecDisp->init( pMessage, ( i - pMessage->m_fields.begin() ) );
i->m_pDisp = pVecDisp;
}
else
i->m_pDisp->Reset();
pDest->vt = VT_DISPATCH;
pDest->pdispVal = i->m_pDisp;
pDest->pdispVal->AddRef();
}
};
class cFieldParser
: public cElementParser
{
public:
class cFieldElement
: public cMessage::cMessageElement
{
public:
cFieldLoader *m_pLoader;
virtual bool load( cMessage::cLoadContext &context )
{
if( !m_pLoader->testValue( context.getMessage()->m_pEndCrack, context.getMessage()->m_pEndData ) )
{
// The element failed, this will usually indicate bad schema
_ASSERTE( FALSE );
return false;
}
context.addField( this, context.getMessage()->m_pEndCrack );
context.getMessage()->m_pEndCrack = reinterpret_cast< BYTE * >( m_pLoader->skip( context.getMessage()->m_pEndCrack ) );
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
m_pLoader->getValue( i->m_pvData, pDest );
}
virtual long getNumber( cMessage::cFieldList::iterator i )
{
return m_pLoader->getNumber( i->m_pvData );
}
};
// Strings
static _bstr_t g_strType;
static _bstr_t g_strName;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
// Locate the data type in the list
_variant_t strDataType = pElement->getAttribute( g_strType );
if( strDataType.vt != VT_BSTR )
{
// Schema error
_ASSERTE( strDataType.vt == VT_BSTR );
return NULL;
}
_bstr_t bstrDataType = strDataType;
cFieldLoader *pField = cFieldLoader::lookup( bstrDataType );
if( pField == NULL )
return parseStruct( context, pElement, bstrDataType );
_variant_t strName = pElement->getAttribute( g_strName );
if( strName.vt != VT_BSTR )
{
_ASSERTE( strName.vt == VT_BSTR );
return NULL;
}
cFieldElement *pFieldElement = new cFieldElement;
pFieldElement->m_strName = strName;
pFieldElement->m_pLoader = pField;
return pFieldElement;
}
cMessage::cMessageElement *parseStruct( cContext &context, MSXML::IXMLDOMElementPtr &pElement, const _bstr_t &strType )
{
// Locate the data type in the list
_variant_t strName = pElement->getAttribute( cFieldParser::g_strName );
if( strName.vt != VT_BSTR )
{
// Schema error
_ASSERTE( strName.vt == VT_BSTR );
return NULL;
}
// We have the field name, now look up data type schema
USES_CONVERSION;
TCHAR szQuery[ 255 ];
::_stprintf( szQuery, _T( "/schema/datatypes/type[@name='%s']" ),
OLE2T( strType ) );
MSXML::IXMLDOMElementPtr pStruct = pElement->ownerDocument->selectSingleNode( szQuery );
if( pStruct.GetInterfacePtr() == NULL )
{
// Could not cross reference the structure
_ASSERTE( pStruct.GetInterfacePtr() != NULL );
return NULL;
}
std::auto_ptr< cStructElement > pStructElement( new cStructElement() );
pStructElement->m_strName = strName;
if( context.parseChildren( pStructElement->m_members, pStruct ) )
return pStructElement.release();
return NULL;
}
};
_bstr_t cFieldParser::g_strType( _T( "type" ) );
_bstr_t cFieldParser::g_strName( _T( "name" ) );
class cMaskParser
: public cElementParser
{
public:
class cMaskElement
: public cMessage::cMessageElement
{
public:
cMessage::cMessageElement *m_pValue;
class cMask
{
public:
DWORD m_dwValue;
DWORD m_dwFirstChild,
m_dwLastChild;
};
typedef std::vector< cMask > cMaskMap;
cMaskMap m_masks;
cMessage::cElementList m_members;
virtual bool load( cMessage::cLoadContext &context )
{
// First, look for our value element in the message
cMessage::cFieldList::iterator iField = context.lookupField( m_pValue );
if( iField == context.getMessage()->m_fields.end() )
{
// Could not find a mask source - most likely a bad name of some kind
_ASSERTE( FALSE );
return false;
}
_ASSERT( iField->m_pSchema == m_pValue );
long nMaskValue = iField->m_pSchema->getNumber( iField );
// Walk through the mask values and load all of the fields in range
for( cMaskMap::iterator i = m_masks.begin(); i != m_masks.end(); ++ i )
{
if( ( nMaskValue & i->m_dwValue ) == 0 )
continue;
// This is a valid mask load up all teh fields in range
cMessage::cElementList::iterator m_end = m_members.begin() + i->m_dwLastChild;
for( cMessage::cElementList::iterator j = m_members.begin() + i->m_dwFirstChild; j != m_end; ++ j )
{
if( !j->get()->load( context ) )
return false;
}
}
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator, LPVARIANT )
{
// This element should never insert itself into the message list
_ASSERTE( FALSE );
}
};
static _bstr_t g_strMask;
static _bstr_t g_strValue;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
_variant_t vName = pElement->getAttribute( cFieldParser::g_strName );
if( vName.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Find a matching element in the schema
cMessage::cMessageElement *pName = context.findElement( vName.bstrVal );
if( pName == NULL )
{
// The mask field was not found
_ASSERTE( pName != NULL );
return NULL;
}
// Create the mask element
std::auto_ptr< cMaskElement > pMaskElement( new cMaskElement );
pMaskElement->m_pValue = pName;
// Walk through each of the mask values
USES_CONVERSION;
MSXML::IXMLDOMNodeListPtr pMaskList = pElement->selectNodes( g_strMask );
for( MSXML::IXMLDOMElementPtr pMask = pMaskList->nextNode(); pMask.GetInterfacePtr() != NULL; pMask = pMaskList->nextNode() )
{
_variant_t vValue = pMask->getAttribute( g_strValue );
if( vValue.vt != VT_BSTR )
{
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Make sure it has the 'hex' prefix
if( vValue.bstrVal[ 0 ] != OLESTR( '0' ) )
{
_ASSERTE( vValue.bstrVal[ 0 ] == OLESTR( '0' ) );
return NULL;
}
if( vValue.bstrVal[ 1 ] != OLESTR( 'x' ) )
{
_ASSERTE( vValue.bstrVal[ 1 ] == OLESTR( 'x' ) );
return NULL;
}
// Attempt to convert the remaining number
long nMaskValue;
if( ::_stscanf( OLE2T( vValue.bstrVal + 2 ), _T( "%X" ), &nMaskValue ) != 1 )
{
// Could not convert value
_ASSERTE( FALSE );
return NULL;
}
long nStartOffset = pMaskElement->m_members.size();
context.parseChildren( pMaskElement->m_members, pMask );
cMaskElement::cMask mask = { nMaskValue, nStartOffset, pMaskElement->m_members.size() };
pMaskElement->m_masks.push_back( mask );
}
return pMaskElement.release();
}
};
_bstr_t cMaskParser::g_strMask( _T( "mask" ) );
_bstr_t cMaskParser::g_strValue( _T( "value" ) );
class cVectorParser
: public cElementParser
{
public:
class cVectorElement
: public cMessage::cMessageElement
{
public:
cMessage::cMessageElement *m_pLength;
std::auto_ptr< cMessage::cMessageElement > m_pStruct;
int m_nSkip;
virtual bool load( cMessage::cLoadContext &context )
{
// First, look for our value element in the message
cMessage::cFieldList::iterator iField = context.lookupField( m_pLength );
if( iField == context.getMessage()->m_fields.end() )
{
// Could not find a mask source - most likely a bad name of some kind
_ASSERTE( FALSE );
return NULL;
}
_ASSERT( iField->m_pSchema == m_pLength );
long nLength = iField->m_pSchema->getNumber( iField ) - m_nSkip;
// Insert a record for ourself
DWORD dwIndex = context.addField( this, NULL );
for( int i = 0; i < nLength; ++ i )
{
// Insert a record for the current struct
if( !m_pStruct->load( cMessage::cLoadContext( &context ) ) )
return false;
}
// Update the used field count
context.groupField( dwIndex );
return true;
}
virtual void getValue( cMessage *pMessage, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
if( i->m_pDisp.p == NULL )
{
// Create the vector object
CComObject< cMessageVector > *pVecDisp;
CComObject< cMessageVector >::CreateInstance( &pVecDisp );
pVecDisp->init( pMessage, ( i - pMessage->m_fields.begin() ) );
i->m_pDisp = pVecDisp;
}
else
i->m_pDisp->Reset();
pDest->vt = VT_DISPATCH;
pDest->pdispVal = i->m_pDisp;
pDest->pdispVal->AddRef();
}
};
static _bstr_t g_strLength,
g_strSkip;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
_variant_t vName = pElement->getAttribute( cFieldParser::g_strName );
if( vName.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
_variant_t vLength = pElement->getAttribute( g_strLength ),
vSkip = pElement->getAttribute( g_strSkip );
if( vLength.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vLength.vt == VT_BSTR );
return NULL;
}
long nSkip = 0;
if( vSkip.vt != VT_NULL )
{
try
{
nSkip = vSkip;
}
catch( ... )
{
// Failed to make the conversion
_ASSERT( FALSE );
return NULL;
}
}
cMessage::cMessageElement *pLength = context.findElement( vLength.bstrVal );
if( pLength == NULL )
{
// The mask field was not found
_ASSERTE( pLength != NULL );
return NULL;
}
std::auto_ptr< cStructElement > pStructElement( new cStructElement );
if( !context.parseChildren( pStructElement->m_members, pElement ) )
return NULL;
cVectorElement *pVector = new cVectorElement;
pVector->m_strName = vName;
pVector->m_pLength = pLength;
pVector->m_nSkip = nSkip;
pVector->m_pStruct = std::auto_ptr< cMessage::cMessageElement >( pStructElement.release() );
return pVector;
}
};
_bstr_t cVectorParser::g_strLength( _T( "length" ) );
_bstr_t cVectorParser::g_strSkip( _T( "skip" ) );
class cSwitchParser
: public cElementParser
{
public:
class cSwitchElement
: public cMessage::cMessageElement
{
public:
cMessage::cMessageElement *m_pValue;
class cCase
{
public:
DWORD m_dwValue;
DWORD m_dwFirstChild,
m_dwLastChild;
};
typedef std::vector< cCase > cCaseMap;
cCaseMap m_cases;
cMessage::cElementList m_members;
virtual bool load( cMessage::cLoadContext &context )
{
// First, look for our value element in the message
cMessage::cFieldList::iterator iField = context.lookupField( m_pValue );
if( iField == context.getMessage()->m_fields.end() )
{
// Could not find a mask source - most likely a bad name of some kind
_ASSERTE( FALSE );
return NULL;
}
_ASSERT( iField->m_pSchema == m_pValue );
long nCaseValue = iField->m_pSchema->getNumber( iField );
// Walk through the mask values and load all of the fields in range
for( cCaseMap::iterator i = m_cases.begin(); i != m_cases.end(); ++ i )
{
if( nCaseValue != i->m_dwValue )
continue;
// This is a valid mask load up all teh fields in range
cMessage::cElementList::iterator m_end = m_members.begin() + i->m_dwLastChild;
for( cMessage::cElementList::iterator j = m_members.begin() + i->m_dwFirstChild; j != m_end; ++ j )
{
if( !j->get()->load( context ) )
return false;
}
// For now we short circuit cases
break;
}
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator, LPVARIANT )
{
// This element should never insert itself into the message list
_ASSERTE( FALSE );
}
};
static _bstr_t g_strCase;
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
_variant_t vName = pElement->getAttribute( cFieldParser::g_strName );
if( vName.vt != VT_BSTR )
{
// It must have the name field
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Find a matching element in the schema
cMessage::cMessageElement *pName = context.findElement( vName.bstrVal );
if( pName == NULL )
{
// The mask field was not found
_ASSERTE( pName != NULL );
return NULL;
}
// Create the mask element
std::auto_ptr< cSwitchElement > pSwitchElement( new cSwitchElement );
pSwitchElement->m_pValue = pName;
// Walk through each of the mask values
USES_CONVERSION;
MSXML::IXMLDOMNodeListPtr pCaseList = pElement->selectNodes( g_strCase );
for( MSXML::IXMLDOMElementPtr pCase = pCaseList->nextNode(); pCase.GetInterfacePtr() != NULL; pCase = pCaseList->nextNode() )
{
_variant_t vValue = pCase->getAttribute( cMaskParser::g_strValue );
if( vValue.vt != VT_BSTR )
{
_ASSERTE( vName.vt == VT_BSTR );
return NULL;
}
// Make sure it has the 'hex' prefix
if( vValue.bstrVal[ 0 ] != OLESTR( '0' ) )
{
_ASSERTE( vValue.bstrVal[ 0 ] == OLESTR( '0' ) );
return NULL;
}
if( vValue.bstrVal[ 1 ] != OLESTR( 'x' ) )
{
_ASSERTE( vValue.bstrVal[ 1 ] == OLESTR( 'x' ) );
return NULL;
}
// Attempt to convert the remaining number
long nCaseValue;
if( ::_stscanf( OLE2T( vValue.bstrVal + 2 ), _T( "%X" ), &nCaseValue ) != 1 )
{
// Could not convert value
_ASSERTE( FALSE );
return NULL;
}
long nStartOffset = pSwitchElement->m_members.size();
context.parseChildren( pSwitchElement->m_members, pCase );
cSwitchElement::cCase _case = { nCaseValue, nStartOffset, pSwitchElement->m_members.size() };
pSwitchElement->m_cases.push_back( _case );
}
return pSwitchElement.release();
}
};
_bstr_t cSwitchParser::g_strCase( _T( "case" ) );
class cAlignParser
: public cElementParser
{
public:
class cAlignElement
: public cMessage::cMessageElement
{
public:
cFieldLoader *m_pLoader;
virtual bool load( cMessage::cLoadContext &context )
{
void *pAlign = m_pLoader->align( context.getMessage()->m_pEndCrack, context.getMessage()->m_pStartCrack );
if( pAlign > context.getMessage()->m_pEndData )
{
_ASSERTE( FALSE );
return false;
}
context.getMessage()->m_pEndCrack = reinterpret_cast< BYTE * >( pAlign );
return true;
}
virtual void getValue( cMessage *, cMessage::cFieldList::iterator i, LPVARIANT pDest )
{
// This should never associate itself with a field
_ASSERTE( FALSE );
}
};
virtual cMessage::cMessageElement *parse( cContext &context, MSXML::IXMLDOMElementPtr &pElement )
{
// Locate the data type in the list
_variant_t strDataType = pElement->getAttribute( cFieldParser::g_strType );
if( strDataType.vt != VT_BSTR )
{
// Schema error
_ASSERTE( strDataType.vt == VT_BSTR );
return NULL;
}
_bstr_t bstrDataType = strDataType;
cFieldLoader *pField = cFieldLoader::lookup( bstrDataType );
if( pField == NULL )
{
_ASSERTE( FALSE );
return NULL;
}
cAlignElement *pAlignElement = new cAlignElement;
pAlignElement->m_pLoader = pField;
return pAlignElement;
}
};
cMessage::cMessageElement *cElementParser::cContext::findElement( const _bstr_t &strElement )
{
for( cContext *pContext = this; pContext != NULL; pContext = pContext->m_pParent )
{
for( cMessage::cElementList::iterator i = m_pElements->begin() + m_dwStartOffset; i != m_pElements->end(); ++ i )
{
if( i->get()->m_strName == strElement )
return i->get();
}
}
return NULL;
}
bool cElementParser::cContext::parseChildren( MSXML::IXMLDOMElementPtr &pElement )
{
MSXML::IXMLDOMNodeListPtr pChildList = pElement->selectNodes( g_strAll );
for( MSXML::IXMLDOMElementPtr pChild = pChildList->nextNode(); pChild.GetInterfacePtr() != NULL; pChild = pChildList->nextNode() )
{
_bstr_t strElementName = pChild->tagName;
cElementParser *pParser = cElementParser::lookup( strElementName );
if( pParser == NULL )
{
// Could not find a parse for this element type
_ASSERTE( FALSE );
return false;
}
cMessage::cMessageElement *pElement = pParser->parse( *this, pChild );
if( pElement == NULL )
return false;
m_pElements->push_back( cMessage::cElementList::value_type( pElement ) );
}
return true;
}
_bstr_t cElementParser::cContext::g_strAll( _T( "*" ) );
bool cElementParser::cContext::parseChildren( cMessage::cElementList &elements, MSXML::IXMLDOMElementPtr &pElement )
{
cContext c( &elements, this );
return c.parseChildren( pElement );
}
cElementParser *cElementParser::lookup( const _bstr_t &strElement )
{
cElementParserMap::iterator i = g_parsers.find( strElement );
if( i == g_parsers.end() )
return NULL;
return i->second.get();
}
void cElementParser::init()
{
addParser( _T( "field" ), new cFieldParser );
addParser( _T( "maskmap" ), new cMaskParser );
addParser( _T( "vector" ), new cVectorParser );
addParser( _T( "switch" ), new cSwitchParser );
addParser( _T( "align" ), new cAlignParser );
}
void cElementParser::term()
{
g_parsers.clear();
}
void cElementParser::addParser( LPCTSTR szName, cElementParser *pParser )
{
g_parsers.insert( cElementParserMap::value_type( szName, std::auto_ptr< cElementParser >( pParser ) ) );
}
cElementParser::cElementParserMap cElementParser::g_parsers;