// 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;