You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
640 lines
18 KiB
640 lines
18 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1991 - 2000.
|
|
//
|
|
// File: CXXFLT.CXX
|
|
//
|
|
// Contents: C and Cxx Filter
|
|
//
|
|
// History: 07-Oct-93 AmyA Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
extern "C" GUID CLSID_CxxIFilter;
|
|
|
|
GUID guidCPlusPlus = { 0x8DEE0300, \
|
|
0x16C2, 0x101B, \
|
|
0xB1, 0x21, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9 };
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::CxxIFilter, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CxxIFilter::CxxIFilter()
|
|
: _state(FilterDone),
|
|
_ulLastTextChunkID(0),
|
|
_ulChunkID(0),
|
|
_pTextFilt(0),
|
|
_pPersFile(0),
|
|
_pPersStream(0),
|
|
_cAttrib(0),
|
|
_pAttrib(0),
|
|
_pTextStream(0),
|
|
_locale(0) // the default locale
|
|
{
|
|
}
|
|
|
|
const FULLPROPSPEC fpsContents = { PSGUID_STORAGE, PRSPEC_PROPID, PID_STG_CONTENTS };
|
|
|
|
BOOL IsContents( FULLPROPSPEC const & fps )
|
|
{
|
|
return ( !memcmp( &fps, &fpsContents, sizeof fpsContents ) );
|
|
} //IsContents
|
|
|
|
BOOL FPSMatch( FULLPROPSPEC const & fpsA, FULLPROPSPEC const & fpsB )
|
|
{
|
|
if ( fpsA.guidPropSet != fpsB.guidPropSet )
|
|
return FALSE;
|
|
|
|
if ( fpsA.psProperty.ulKind != fpsB.psProperty.ulKind )
|
|
return FALSE;
|
|
|
|
if ( PRSPEC_PROPID == fpsA.psProperty.ulKind )
|
|
return ( fpsA.psProperty.propid == fpsB.psProperty.propid );
|
|
|
|
if ( PRSPEC_LPWSTR != fpsA.psProperty.ulKind )
|
|
return FALSE;
|
|
|
|
return ( !wcscmp( fpsA.psProperty.lpwstr,
|
|
fpsB.psProperty.lpwstr ) );
|
|
} //FPSMatch
|
|
|
|
void FPSCopy( FULLPROPSPEC & fpsTo, FULLPROPSPEC const & fpsFrom )
|
|
{
|
|
fpsTo.guidPropSet = fpsFrom.guidPropSet;
|
|
fpsTo.psProperty.ulKind = fpsFrom.psProperty.ulKind;
|
|
|
|
if ( PRSPEC_PROPID == fpsFrom.psProperty.ulKind )
|
|
{
|
|
fpsTo.psProperty.propid = fpsFrom.psProperty.propid;
|
|
return;
|
|
}
|
|
|
|
if ( PRSPEC_LPWSTR == fpsFrom.psProperty.ulKind )
|
|
{
|
|
unsigned cwc = 1 + wcslen( fpsFrom.psProperty.lpwstr );
|
|
fpsTo.psProperty.lpwstr = (LPWSTR) CoTaskMemAlloc( cwc );
|
|
wcscpy( fpsTo.psProperty.lpwstr, fpsFrom.psProperty.lpwstr );
|
|
}
|
|
} //FPSCopy
|
|
|
|
void FPSFree( FULLPROPSPEC &fps )
|
|
{
|
|
if ( ( PRSPEC_LPWSTR == fps.psProperty.ulKind ) &&
|
|
( 0 != fps.psProperty.lpwstr ) )
|
|
{
|
|
CoTaskMemFree( fps.psProperty.lpwstr );
|
|
fps.psProperty.lpwstr = 0;
|
|
}
|
|
} //FPSFree
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::~CxxIFilter, public
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CxxIFilter::~CxxIFilter()
|
|
{
|
|
delete [] _pAttrib;
|
|
|
|
if ( _pTextFilt )
|
|
_pTextFilt->Release();
|
|
|
|
if ( _pPersFile )
|
|
_pPersFile->Release();
|
|
|
|
if ( _pPersStream )
|
|
_pPersStream->Release();
|
|
|
|
delete _pTextStream;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::Init, public
|
|
//
|
|
// Synopsis: Initializes instance of text filter
|
|
//
|
|
// Arguments: [grfFlags] -- flags for filter behavior
|
|
// [cAttributes] -- number of attributes in array aAttributes
|
|
// [aAttributes] -- array of attributes
|
|
// [pfBulkyObject] -- indicates whether this object is a
|
|
// bulky object
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::Init( ULONG grfFlags,
|
|
ULONG cAttributes,
|
|
FULLPROPSPEC const * aAttributes,
|
|
ULONG * pFlags )
|
|
{
|
|
CTranslateSystemExceptions translate;
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
TRY
|
|
{
|
|
_ulLastTextChunkID = 0;
|
|
_ulChunkID = 0;
|
|
|
|
if( cAttributes > 0 )
|
|
{
|
|
if ( 0 == aAttributes )
|
|
return E_INVALIDARG;
|
|
|
|
_state = FilterProp;
|
|
|
|
_cAttrib = cAttributes;
|
|
if ( 0 != _pAttrib )
|
|
{
|
|
delete [] _pAttrib;
|
|
_pAttrib = 0;
|
|
}
|
|
|
|
_pAttrib = new CFps [_cAttrib];
|
|
|
|
for ( ULONG i = 0; i < cAttributes; i++ )
|
|
{
|
|
if ( _state != FilterContents && IsContents( aAttributes[i] ) )
|
|
_state = FilterContents;
|
|
|
|
_pAttrib[i].Copy( aAttributes[i] );
|
|
}
|
|
}
|
|
else if ( 0 == grfFlags || (grfFlags & IFILTER_INIT_APPLY_INDEX_ATTRIBUTES) )
|
|
{
|
|
_state = FilterContents;
|
|
}
|
|
else
|
|
{
|
|
_state = FilterDone;
|
|
}
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
sc = e.GetErrorCode();
|
|
}
|
|
END_CATCH;
|
|
|
|
if ( FAILED( sc ) )
|
|
return sc;
|
|
|
|
return _pTextFilt->Init( 0,
|
|
1,
|
|
&fpsContents,
|
|
pFlags );
|
|
} //Init
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::GetChunk, public
|
|
//
|
|
// Synopsis: Gets the next chunk and returns chunk information in pStat
|
|
//
|
|
// Arguments: [pStat] -- for chunk information
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::GetChunk( STAT_CHUNK * pStat )
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
CTranslateSystemExceptions translate;
|
|
|
|
TRY
|
|
{
|
|
if (_state == FilterNextProp)
|
|
{
|
|
_state = FilterProp;
|
|
}
|
|
//
|
|
// All chunks of plain text come first.
|
|
//
|
|
|
|
if ( _state == FilterContents )
|
|
{
|
|
sc = _pTextFilt->GetChunk( pStat );
|
|
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
pStat->locale = 0; // use the default word breaker
|
|
_locale = 0;
|
|
_ulLastTextChunkID = pStat->idChunk;
|
|
}
|
|
else if ( sc == FILTER_E_END_OF_CHUNKS )
|
|
{
|
|
_ulChunkID = _ulLastTextChunkID;
|
|
|
|
ULONG Flags;
|
|
|
|
sc = _pTextFilt->Init( 0,
|
|
1,
|
|
&fpsContents,
|
|
&Flags );
|
|
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
delete _pTextStream;
|
|
_pTextStream = new CFilterTextStream (_pTextFilt);
|
|
if (SUCCEEDED (_pTextStream->GetStatus()))
|
|
{
|
|
_cxxParse.Init( _pTextStream );
|
|
_state = FilterProp;
|
|
}
|
|
else
|
|
_state = FilterDone;
|
|
}
|
|
else
|
|
_state = FilterDone;
|
|
}
|
|
}
|
|
|
|
if ( _state == FilterProp && SUCCEEDED(sc) )
|
|
{
|
|
while ( TRUE )
|
|
{
|
|
if (_cxxParse.Parse())
|
|
{
|
|
pStat->attribute.guidPropSet = guidCPlusPlus;
|
|
pStat->attribute.psProperty = _cxxParse.GetAttribute();
|
|
|
|
for ( unsigned i = 0; i < _cAttrib; i++ )
|
|
if ( _pAttrib[i].IsMatch( pStat->attribute ) )
|
|
break;
|
|
|
|
if ( _cAttrib == 0 || i < _cAttrib ) // Property should be returned
|
|
{
|
|
pStat->idChunk = ++_ulChunkID;
|
|
pStat->breakType = CHUNK_EOS;
|
|
pStat->flags = CHUNK_TEXT;
|
|
pStat->locale = _locale;
|
|
|
|
FILTERREGION regionSource;
|
|
// what's the source of this derived property?
|
|
_cxxParse.GetRegion ( regionSource );
|
|
pStat->idChunkSource = regionSource.idChunk;
|
|
pStat->cwcStartSource = regionSource.cwcStart;
|
|
pStat->cwcLenSource = regionSource.cwcExtent;
|
|
|
|
sc = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_state = FilterValue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( _state == FilterNextValue )
|
|
{
|
|
_cxxParse.SkipValue();
|
|
_state = FilterValue;
|
|
}
|
|
|
|
if ( _state == FilterValue )
|
|
{
|
|
while ( TRUE )
|
|
{
|
|
if ( _cxxParse.GetValueAttribute( pStat->attribute.psProperty ) )
|
|
{
|
|
pStat->attribute.guidPropSet = guidCPlusPlus;
|
|
|
|
for ( unsigned i = 0; i < _cAttrib; i++ )
|
|
if ( _pAttrib[i].IsMatch( pStat->attribute ) )
|
|
break;
|
|
|
|
if ( _cAttrib == 0 || i < _cAttrib ) // Property should be returned
|
|
{
|
|
pStat->flags = CHUNK_VALUE;
|
|
pStat->locale = _locale;
|
|
|
|
_state = FilterNextValue;
|
|
sc = S_OK;
|
|
break;
|
|
}
|
|
else
|
|
_cxxParse.SkipValue();
|
|
}
|
|
else
|
|
{
|
|
_state = FilterDone;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_state == FilterDone || !SUCCEEDED(sc))
|
|
{
|
|
sc = FILTER_E_END_OF_CHUNKS;
|
|
_state = FilterDone;
|
|
}
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
sc = e.GetErrorCode();
|
|
}
|
|
END_CATCH;
|
|
|
|
return sc;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::GetText, public
|
|
//
|
|
// Synopsis: Retrieves text from current chunk
|
|
//
|
|
// Arguments: [pcwcBuffer] -- count of characters in buffer
|
|
// [awcBuffer] -- buffer for text
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::GetText( ULONG * pcwcBuffer,
|
|
WCHAR * awcBuffer )
|
|
{
|
|
if ( _state == FilterValue || _state == FilterNextValue )
|
|
return FILTER_E_NO_TEXT;
|
|
|
|
if ( _state == FilterContents )
|
|
{
|
|
return _pTextFilt->GetText( pcwcBuffer, awcBuffer );
|
|
}
|
|
else if ( _state == FilterProp )
|
|
{
|
|
|
|
if ( _cxxParse.GetTokens( pcwcBuffer, awcBuffer ))
|
|
{
|
|
_state = FilterNextProp;
|
|
return FILTER_S_LAST_TEXT;
|
|
}
|
|
else
|
|
return S_OK;
|
|
}
|
|
else if ( _state == FilterNextProp )
|
|
{
|
|
return FILTER_E_NO_MORE_TEXT;
|
|
}
|
|
else
|
|
{
|
|
Win4Assert ( _state == FilterDone );
|
|
return FILTER_E_NO_MORE_TEXT;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::GetValue, public
|
|
//
|
|
// Synopsis: Not implemented for the text filter
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::GetValue( PROPVARIANT ** ppPropValue )
|
|
{
|
|
if ( _state == FilterContents )
|
|
return _pTextFilt->GetValue( ppPropValue );
|
|
|
|
if ( _state == FilterDone )
|
|
return FILTER_E_NO_MORE_VALUES;
|
|
|
|
if ( _state != FilterNextValue )
|
|
return FILTER_E_NO_VALUES;
|
|
|
|
*ppPropValue = _cxxParse.GetValue();
|
|
_state = FilterValue;
|
|
|
|
if ( 0 == *ppPropValue )
|
|
return FILTER_E_NO_MORE_VALUES;
|
|
else
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::BindRegion, public
|
|
//
|
|
// Synopsis: Creates moniker or other interface for text indicated
|
|
//
|
|
// Arguments: [origPos] -- location of text
|
|
// [riid] -- Interface Id
|
|
// [ppunk] -- returned interface
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::BindRegion( FILTERREGION origPos,
|
|
REFIID riid,
|
|
void ** ppunk )
|
|
{
|
|
return _pTextFilt->BindRegion( origPos, riid, ppunk );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::GetClassID, public
|
|
//
|
|
// Synopsis: Returns the class id of this class.
|
|
//
|
|
// Arguments: [pClassID] -- the class id
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::GetClassID( CLSID * pClassID )
|
|
{
|
|
*pClassID = CLSID_CxxIFilter;
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::IsDirty, public
|
|
//
|
|
// Synopsis: Always returns S_FALSE since this class is read-only.
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::IsDirty()
|
|
{
|
|
return S_FALSE; // Since the filter is read-only, there will never be
|
|
// changes to the file.
|
|
}
|
|
|
|
typedef HRESULT (__stdcall * PFnLoadTextFilter)( WCHAR const * pwcPath,
|
|
IFilter ** ppIFilter );
|
|
|
|
PFnLoadTextFilter g_pLoadTextFilter = 0;
|
|
|
|
SCODE MyLoadTextFilter( WCHAR const *pwc, IFilter **ppFilter )
|
|
{
|
|
if ( 0 == g_pLoadTextFilter )
|
|
{
|
|
// Dummy call to CIState to force query.dll to be always loaded
|
|
|
|
CIState( 0, 0, 0 );
|
|
|
|
g_pLoadTextFilter = (PFnLoadTextFilter) GetProcAddress( GetModuleHandle( L"query.dll" ), "LoadTextFilter" );
|
|
|
|
if ( 0 == g_pLoadTextFilter )
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return g_pLoadTextFilter( pwc, ppFilter );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::Load, public
|
|
//
|
|
// Synopsis: Loads the indicated file
|
|
//
|
|
// Arguments: [pszFileName] -- the file name
|
|
// [dwMode] -- the mode to load the file in
|
|
//
|
|
// History: 07-Oct-93 AmyA Created.
|
|
//
|
|
// Notes: dwMode must be either 0 or STGM_READ.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::Load(LPCWSTR pszFileName, DWORD dwMode)
|
|
{
|
|
if ( 0 != _pTextFilt )
|
|
{
|
|
_pTextFilt->Release();
|
|
_pTextFilt = 0;
|
|
}
|
|
|
|
if ( 0 != _pPersFile )
|
|
{
|
|
_pPersFile->Release();
|
|
_pPersFile = 0;
|
|
}
|
|
|
|
if ( 0 != _pPersStream )
|
|
{
|
|
_pPersStream->Release();
|
|
_pPersStream = 0;
|
|
}
|
|
|
|
SCODE sc = MyLoadTextFilter( pszFileName, &_pTextFilt );
|
|
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
// Load file
|
|
|
|
sc = _pTextFilt->QueryInterface( IID_IPersistFile, (void **) &_pPersFile );
|
|
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
sc = _pPersFile->Load( pszFileName, dwMode );
|
|
}
|
|
else
|
|
{
|
|
_pTextFilt->Release();
|
|
_pTextFilt = 0;
|
|
}
|
|
}
|
|
|
|
return sc;
|
|
} //Load
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::Load( IStream * pStm )
|
|
{
|
|
SCODE sc = MyLoadTextFilter( 0, &_pTextFilt );
|
|
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
// Load file
|
|
|
|
sc = _pTextFilt->QueryInterface( IID_IPersistStream, (void **) &_pPersStream );
|
|
|
|
if ( SUCCEEDED(sc) )
|
|
{
|
|
sc = _pPersStream->Load( pStm );
|
|
}
|
|
else
|
|
{
|
|
_pTextFilt->Release();
|
|
_pTextFilt = 0;
|
|
}
|
|
}
|
|
|
|
return sc;
|
|
} //Load
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::Save, public
|
|
//
|
|
// Synopsis: Always returns E_FAIL, since the file is opened read-only
|
|
//
|
|
// History: 16-Jul-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::Save(LPCWSTR pszFileName, BOOL fRemember)
|
|
{
|
|
return E_FAIL; // cannot be saved since it is read-only
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::SaveCompleted, public
|
|
//
|
|
// Synopsis: Always returns S_OK since the file is opened read-only
|
|
//
|
|
// History: 16-Jul-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::SaveCompleted(LPCWSTR pszFileName)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CxxIFilter::GetCurFile, public
|
|
//
|
|
// Synopsis: Returns a copy of the current file name
|
|
//
|
|
// Arguments: [ppszFileName] -- where the copied string is returned.
|
|
//
|
|
// History: 09-Aug-93 AmyA Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE STDMETHODCALLTYPE CxxIFilter::GetCurFile(LPWSTR * ppszFileName)
|
|
{
|
|
return _pPersFile->GetCurFile( ppszFileName );
|
|
}
|