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>
727 lines
21 KiB
C++
727 lines
21 KiB
C++
// MessageParsers.cpp
|
|
// Implementation of parsers and runtime objects for parsing message data
|
|
|
|
#include "StdAfx.h"
|
|
#include "DecalNet.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< cMessageStructIter > *pVecDisp;
|
|
CComObject< cMessageStructIter >::CreateInstance( &pVecDisp );
|
|
|
|
pVecDisp->init( pMessage, ( i - pMessage->m_fields.begin() ) );
|
|
i->m_pDisp = pVecDisp;
|
|
}
|
|
else
|
|
i->m_pDisp->Reset();
|
|
|
|
pDest->vt = VT_DISPATCH;
|
|
i->m_pDisp->QueryInterface ( IID_IMessageMember, reinterpret_cast< LPVOID * > ( &pDest->pdispVal ) );
|
|
}
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
VSBridge::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
|
|
VSBridge::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 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;
|
|
}
|
|
};
|
|
|
|
class cVectorParser
|
|
: public cElementParser
|
|
{
|
|
public:
|
|
class cVectorElement
|
|
: public cMessage::cMessageElement
|
|
{
|
|
public:
|
|
cMessage::cMessageElement *m_pLength;
|
|
VSBridge::auto_ptr< cMessage::cMessageElement > m_pStruct;
|
|
int m_nSkip;
|
|
|
|
DWORD m_dwMask;
|
|
|
|
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;
|
|
|
|
if (m_dwMask != 0)
|
|
{
|
|
DWORD dwTemp = (DWORD) nLength & m_dwMask;
|
|
DWORD dwTempMask = m_dwMask;
|
|
|
|
// Shift the length field right as far as we can.
|
|
while (! (dwTempMask & 0x1))
|
|
{
|
|
dwTempMask >>= 1;
|
|
dwTemp >>= 1;
|
|
}
|
|
|
|
nLength = (long) dwTemp;
|
|
}
|
|
|
|
// 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< cMessageVectorIter > *pVecDisp;
|
|
CComObject< cMessageVectorIter >::CreateInstance( &pVecDisp );
|
|
|
|
pVecDisp->init( pMessage, ( i - pMessage->m_fields.begin() ) );
|
|
i->m_pDisp = pVecDisp;
|
|
}
|
|
else
|
|
i->m_pDisp->Reset();
|
|
|
|
pDest->vt = VT_DISPATCH;
|
|
i->m_pDisp->QueryInterface ( IID_IMessageMember, reinterpret_cast< LPVOID * > ( &pDest->pdispVal ) );
|
|
}
|
|
};
|
|
|
|
static _bstr_t g_strLength,
|
|
g_strSkip,
|
|
g_strMask;
|
|
|
|
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 ),
|
|
vMask = pElement->getAttribute( g_strMask );
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
DWORD dwMask = 0;
|
|
if( vMask.vt != VT_NULL )
|
|
{
|
|
dwMask = ::wcstoul (vMask.bstrVal, NULL, 16);
|
|
}
|
|
|
|
cMessage::cMessageElement *pLength = context.findElement( vLength.bstrVal );
|
|
if( pLength == NULL )
|
|
{
|
|
// The mask field was not found
|
|
_ASSERTE( pLength != NULL );
|
|
return NULL;
|
|
}
|
|
|
|
VSBridge::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_dwMask = dwMask;
|
|
pVector->m_pStruct = VSBridge::auto_ptr< cMessage::cMessageElement >( pStructElement.release() );
|
|
|
|
return pVector;
|
|
}
|
|
};
|
|
|
|
_bstr_t cVectorParser::g_strLength( _T( "length" ) );
|
|
_bstr_t cVectorParser::g_strSkip( _T( "skip" ) );
|
|
_bstr_t cVectorParser::g_strMask( _T( "mask" ) );
|
|
|
|
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
|
|
VSBridge::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" ) );
|
|
|
|
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, VSBridge::auto_ptr< cElementParser >( pParser ) ) );
|
|
}
|
|
|
|
cElementParser::cElementParserMap cElementParser::g_parsers;
|