// Prefilter.cpp : Implementation of cPrefilter #include "stdafx.h" #include "DecalFilters.h" #include "Prefilter.h" ///////////////////////////////////////////////////////////////////////////// // cPrefilter class cFieldRule : public cPrefilter::cFilterRule { public: _variant_t m_strField; bool m_bReset; static _bstr_t _strField, _strReset; cFieldRule() : m_bReset( false ) { } bool loadField( MSXML::IXMLDOMElementPtr &pElement ) { m_strField = pElement->getAttribute( _strField ); _variant_t vReset = pElement->getAttribute( _strReset ); if( vReset.vt != VT_NULL ) m_bReset = vReset; #ifdef _DEBUG if( m_bReset ) _ASSERTE( m_strField.vt == VT_BSTR ); #endif return true; } void get( _variant_t &vValue, IMessageIterator *pMsg ) { if( m_bReset ) pMsg->Reset(); if( m_strField.vt == VT_BSTR ) pMsg->get_Next( m_strField, &vValue ); else pMsg->get_Current( &vValue ); } }; class cEndRule : public cPrefilter::cFilterRule { public: virtual bool test( IMessageIterator * ) { return true; } }; _bstr_t cFieldRule::_strField( _T( "field" ) ); _bstr_t cFieldRule::_strReset( _T( "reset" ) ); class cTestRule : public cFieldRule { public: virtual bool test( IMessageIterator *pMsg ) { _variant_t vValue; get( vValue, pMsg ); return ( vValue.vt != VT_NULL ); } }; class cEqualsRule : public cFieldRule { public: _variant_t m_vValue; virtual bool test( IMessageIterator *pMsg ) { _variant_t vValue; get( vValue, pMsg ); if( vValue.vt == VT_NULL || m_vValue.vt == VT_NULL ) // Null values are never equal, use cTestRule return false; if( vValue.vt != m_vValue.vt ) { // Attempt to convert them to the same type - this will typically happen // the first time the rule is invoked. This will speed up comparisons // in the future HRESULT hRes = ::VariantChangeType( &m_vValue, &m_vValue, 0, vValue.vt ); if( FAILED( hRes ) ) { _ASSERT( FALSE ); // Could not convert the value - clear it so this rule becomes, disabled ::VariantClear( &m_vValue ); m_vValue.vt = VT_NULL; return false; } } // Compare the values return( ::VarCmp( &vValue, &m_vValue, LOCALE_USER_DEFAULT, 0 ) == VARCMP_EQ ); } }; class cContainsRule : public cFieldRule { public: _bstr_t m_strValue; virtual bool test( IMessageIterator *pMsg ) { _variant_t vValue; get( vValue, pMsg ); if( vValue.vt != VT_BSTR ) // Null values are never equal, use cTestRule return false; // Use the std::algorithm search LPOLESTR szValueBegin = vValue.bstrVal, szValueEnd = vValue.bstrVal + ::SysStringLen( vValue.bstrVal ), szSearchBegin = m_strValue, szSearchEnd = szSearchBegin + m_strValue.length(); LPOLESTR szFound = std::search( szValueBegin, szValueEnd, szSearchBegin, szSearchEnd ); return( szFound != szValueEnd ); } }; class cMaskRule : public cFieldRule { public: long m_nValue; virtual bool test( IMessageIterator *pMsg ) { long nValue; // Custom get HRESULT hRes = pMsg->get_NextInt( m_strField.bstrVal, &nValue ); if( FAILED( hRes ) ) return false; return !!( nValue & m_nValue ); } }; bool cPrefilter::testRules( cFilterRule *pRule, IMessageIterator *pMsg ) { if( !pRule->test( pMsg ) ) return false; // If there is a fire ID, fire it now if( pRule->m_nFire != cFilterRule::eFireChildren ) { CComPtr< IMessage > pMsgObj; pMsg->get_Message( &pMsgObj ); Fire_Event( pRule->m_nFire, pMsgObj ); return true; } // If it has no children ... carry on if( pRule->m_childRules.empty() ) return true; // Test our children for( cFilterRule::cFilterRuleList::iterator i = pRule->m_childRules.begin(); i != pRule->m_childRules.end(); ++ i ) { if( testRules( i->get(), pMsg ) ) return true; } return false; } cPrefilter::cFilterRule *cPrefilter::loadRule( MSXML::IXMLDOMElementPtr &pElement ) { USES_CONVERSION; // Load the current rule, first figure out the type static _bstr_t _strMessage( _T( "message" ) ), _strFire( _T( "fire" ) ), _strTest( _T( "test" ) ), _strEqual( _T( "equal" ) ), _strContain( _T( "contains" ) ), _strMask( _T( "mask" ) ), _strField( _T( "field" ) ), _strNext( _T( "next" ) ), _strValue( _T( "value" ) ), _strEnd( _T( "end" ) ); try { _bstr_t strElement = pElement->tagName; VSBridge::auto_ptr< cFilterRule > pFilter; if( strElement == _strMessage || strElement == _strFire ) { pFilter = VSBridge::auto_ptr< cFilterRule >( new cFilterRule ); } else if( strElement == _strTest ) { cTestRule *pRule = new cTestRule; pFilter = VSBridge::auto_ptr< cFilterRule >( pRule ); if( !pRule->loadField( pElement ) ) return NULL; } else if( strElement == _strEqual ) { cEqualsRule *pRule = new cEqualsRule; pFilter = VSBridge::auto_ptr< cFilterRule >( pRule ); if( !pRule->loadField( pElement ) ) return NULL; pRule->m_vValue = pElement->getAttribute( _strValue ); if( pRule->m_vValue.vt == VT_NULL ) { // Missing required field _ASSERT( FALSE ); return false; } } else if( strElement == _strContain ) { cContainsRule *pRule = new cContainsRule; pFilter = VSBridge::auto_ptr< cFilterRule >( pRule ); if( !pRule->loadField( pElement ) ) return NULL; _variant_t vValue = pElement->getAttribute( _strValue ); if( vValue.vt != VT_BSTR ) { // Missing required field or incorrect type _ASSERT( FALSE ); return false; } pRule->m_strValue = vValue; } else if( strElement == _strMask ) { cMaskRule *pRule = new cMaskRule; pFilter = VSBridge::auto_ptr< cFilterRule >( pRule ); if( !pRule->loadField( pElement ) ) return NULL; _variant_t vValue = pElement->getAttribute( _strValue ); if( vValue.vt == VT_NULL ) { // Missing required field _ASSERT( FALSE ); return false; } // Attempt to convert the value from hex if( ::_stscanf( OLE2T( vValue.bstrVal ), _T( "%X" ), &pRule->m_nValue ) != 1 ) { _ASSERT( FALSE ); return NULL; } } else if( strElement == _strEnd ) pFilter = VSBridge::auto_ptr< cFilterRule >( new cEndRule ); else return NULL; _variant_t vFire = pElement->getAttribute( _strFire ); // Convert the fire type, then carry on if( vFire.vt != VT_NULL ) pFilter->m_nFire = vFire; else { // Select all children - all element children MSXML::IXMLDOMNodeListPtr pRules = pElement->selectNodes( _T( "*" ) ); for( MSXML::IXMLDOMElementPtr pChildRule = pRules->nextNode(); pChildRule; pChildRule = pRules->nextNode() ) { VSBridge::auto_ptr< cFilterRule > pChildFilter( loadRule( pChildRule ) ); if( pChildFilter.get() == NULL ) continue; // Load the children pFilter->m_childRules.push_back( pChildFilter ); } } return pFilter.release(); } catch( _com_error &e ) { HRESULT hRes = e.Error(); _ASSERTE( FALSE ); } return NULL; } STDMETHODIMP cPrefilter::Initialize(INetService *pService) { USES_CONVERSION; CComPtr< IDecal > pDecal; pService->get_Decal( &pDecal ); CComBSTR strMappedFile; HRESULT hRes = pDecal->MapPath( m_strFile, &strMappedFile ); if( FAILED( hRes ) ) // Bad token in the filename return hRes; MSXML::IXMLDOMDocumentPtr pFilter; hRes = ::CoCreateInstance( __uuidof( MSXML::DOMDocument ), NULL, CLSCTX_INPROC_SERVER, __uuidof( MSXML::IXMLDOMDocument ), reinterpret_cast< void ** >( &pFilter ) ); if( FAILED( hRes ) ) return hRes; bool bLoad = !!pFilter->load( strMappedFile.m_str ); if( !bLoad ) { // The document failed to load, get the error info for posterity MSXML::IXMLDOMParseErrorPtr pErr = pFilter->parseError; long nCode = pErr->errorCode; long nFilePos = pErr->filepos; long nLine = pErr->line; long nLinePos = pErr->linepos; _bstr_t strReason = pErr->reason; _bstr_t strText = pErr->srcText; TCHAR szError[ 1024 ]; ::_stprintf( szError, _T( "0x%08X (%i, %i): %s" ), nCode, nLine, nLinePos, OLE2T( strReason ) ); /* long nHWND; m_pSite->get_HWND( &nHWND ); */ ::MessageBox( NULL, szError, _T( "XML Parse Error" ), MB_ICONERROR | MB_OK ); // Give the user a chance to break and look at this lovely info _ASSERTE( FALSE ); return E_FAIL; } // Looking good - now we'll load el'schema MSXML::IXMLDOMNodeListPtr pMessages = pFilter->selectNodes( _T( "/filter/message" ) ); for( MSXML::IXMLDOMElementPtr pMessage = pMessages->nextNode(); pMessage; pMessage = pMessages->nextNode() ) { _variant_t vMessage = pMessage->getAttribute( _T( "type" ) ), vFire = pMessage->getAttribute( _T( "fire" ) ); if( vMessage.vt != VT_BSTR ) { _ASSERT( FALSE ); continue; } // Attempt to convert the message type long nMessage; if( ::_stscanf( OLE2T( vMessage.bstrVal ), _T( "%X" ), &nMessage ) != 1 ) { // Invalid message ID format _ASSERT( FALSE ); continue; } VSBridge::auto_ptr pMessageRule( loadRule( pMessage ) ); if( pMessageRule.get() == NULL ) continue; m_messageRules.insert( cMessageRuleList::value_type( nMessage, pMessageRule ) ); } return S_OK; } STDMETHODIMP cPrefilter::DispatchServer( IMessage2 *pMsg ) { long nID; pMsg->get_Type( &nID ); // Look for a type cMessageRuleList::iterator i_msg = m_messageRules.find( nID ); if( i_msg == m_messageRules.end() ) return S_OK; CComPtr< IMessageIterator > pMembers; pMsg->get_Begin( &pMembers ); testRules( i_msg->second.get(), pMembers ); return S_OK; } STDMETHODIMP cPrefilter::CreateInstance( IDecalEnum *pInitData, REFIID iid, LPVOID *pObject ) { CComVariant vFile; HRESULT hRes = pInitData->get_Property( _bstr_t( "File" ), &vFile ); if( FAILED( hRes ) ) return hRes; if( vFile.vt != VT_BSTR ) { // The surrogate must know the file _ASSERT( FALSE ); return E_FAIL; } m_strFile = vFile.bstrVal; return static_cast< IDecalSurrogate * >( this )->QueryInterface( iid, pObject ); }