Source code of Windows XP (NT5)
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.

593 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: CXXFLT.CXX
  7. //
  8. // Contents: C and Cxx Filter
  9. //
  10. // History: 07-Oct-93 AmyA Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. extern "C" GUID CLSID_CxxIFilter;
  16. GUID guidCPlusPlus = { 0x8DEE0300, \
  17. 0x16C2, 0x101B, \
  18. 0xB1, 0x21, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9 };
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Member: CxxIFilter::CxxIFilter, public
  22. //
  23. // Synopsis: Constructor
  24. //
  25. // History: 07-Oct-93 AmyA Created.
  26. //
  27. //----------------------------------------------------------------------------
  28. CxxIFilter::CxxIFilter()
  29. : _state(FilterDone),
  30. _ulLastTextChunkID(0),
  31. _ulChunkID(0),
  32. _pTextFilt(0),
  33. _pPersFile(0),
  34. _cAttrib(0),
  35. _pAttrib(0),
  36. _pTextStream(0),
  37. _locale(0) // the default locale
  38. {
  39. }
  40. const FULLPROPSPEC fpsContents = { PSGUID_STORAGE, PRSPEC_PROPID, PID_STG_CONTENTS };
  41. BOOL IsContents( FULLPROPSPEC const & fps )
  42. {
  43. return ( !memcmp( &fps, &fpsContents, sizeof fpsContents ) );
  44. } //IsContents
  45. BOOL FPSMatch( FULLPROPSPEC const & fpsA, FULLPROPSPEC const & fpsB )
  46. {
  47. if ( fpsA.guidPropSet != fpsB.guidPropSet )
  48. return FALSE;
  49. if ( fpsA.psProperty.ulKind != fpsB.psProperty.ulKind )
  50. return FALSE;
  51. if ( PRSPEC_PROPID == fpsA.psProperty.ulKind )
  52. return ( fpsA.psProperty.propid == fpsB.psProperty.propid );
  53. if ( PRSPEC_LPWSTR != fpsA.psProperty.ulKind )
  54. return FALSE;
  55. return ( !wcscmp( fpsA.psProperty.lpwstr,
  56. fpsB.psProperty.lpwstr ) );
  57. } //FPSMatch
  58. void FPSCopy( FULLPROPSPEC & fpsTo, FULLPROPSPEC const & fpsFrom )
  59. {
  60. fpsTo.guidPropSet = fpsFrom.guidPropSet;
  61. fpsTo.psProperty.ulKind = fpsFrom.psProperty.ulKind;
  62. if ( PRSPEC_PROPID == fpsFrom.psProperty.ulKind )
  63. {
  64. fpsTo.psProperty.propid = fpsFrom.psProperty.propid;
  65. return;
  66. }
  67. if ( PRSPEC_LPWSTR == fpsFrom.psProperty.ulKind )
  68. {
  69. unsigned cwc = 1 + wcslen( fpsFrom.psProperty.lpwstr );
  70. fpsTo.psProperty.lpwstr = (LPWSTR) CoTaskMemAlloc( cwc );
  71. wcscpy( fpsTo.psProperty.lpwstr, fpsFrom.psProperty.lpwstr );
  72. }
  73. } //FPSCopy
  74. void FPSFree( FULLPROPSPEC &fps )
  75. {
  76. if ( ( PRSPEC_LPWSTR == fps.psProperty.ulKind ) &&
  77. ( 0 != fps.psProperty.lpwstr ) )
  78. {
  79. CoTaskMemFree( fps.psProperty.lpwstr );
  80. fps.psProperty.lpwstr = 0;
  81. }
  82. } //FPSFree
  83. //+---------------------------------------------------------------------------
  84. //
  85. // Member: CxxIFilter::~CxxIFilter, public
  86. //
  87. // Synopsis: Destructor
  88. //
  89. // History: 07-Oct-93 AmyA Created.
  90. //
  91. //----------------------------------------------------------------------------
  92. CxxIFilter::~CxxIFilter()
  93. {
  94. delete [] _pAttrib;
  95. if ( _pTextFilt )
  96. _pTextFilt->Release();
  97. if ( _pPersFile )
  98. _pPersFile->Release();
  99. delete _pTextStream;
  100. }
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Member: CxxIFilter::Init, public
  104. //
  105. // Synopsis: Initializes instance of text filter
  106. //
  107. // Arguments: [grfFlags] -- flags for filter behavior
  108. // [cAttributes] -- number of attributes in array aAttributes
  109. // [aAttributes] -- array of attributes
  110. // [pfBulkyObject] -- indicates whether this object is a
  111. // bulky object
  112. //
  113. // History: 07-Oct-93 AmyA Created.
  114. //
  115. //----------------------------------------------------------------------------
  116. SCODE STDMETHODCALLTYPE CxxIFilter::Init( ULONG grfFlags,
  117. ULONG cAttributes,
  118. FULLPROPSPEC const * aAttributes,
  119. ULONG * pFlags )
  120. {
  121. CTranslateSystemExceptions translate;
  122. SCODE sc = S_OK;
  123. TRY
  124. {
  125. _ulLastTextChunkID = 0;
  126. _ulChunkID = 0;
  127. if( cAttributes > 0 )
  128. {
  129. _state = FilterProp;
  130. _cAttrib = cAttributes;
  131. if ( 0 != _pAttrib )
  132. {
  133. delete [] _pAttrib;
  134. _pAttrib = 0;
  135. }
  136. _pAttrib = new CFps [_cAttrib];
  137. for ( ULONG i = 0; i < cAttributes; i++ )
  138. {
  139. if ( _state != FilterContents && IsContents( aAttributes[i] ) )
  140. _state = FilterContents;
  141. _pAttrib[i].Copy( aAttributes[i] );
  142. }
  143. }
  144. else if ( 0 == grfFlags || (grfFlags & IFILTER_INIT_APPLY_INDEX_ATTRIBUTES) )
  145. {
  146. _state = FilterContents;
  147. }
  148. else
  149. {
  150. _state = FilterDone;
  151. }
  152. }
  153. CATCH(CException, e)
  154. {
  155. sc = e.GetErrorCode();
  156. }
  157. END_CATCH;
  158. if ( FAILED( sc ) )
  159. return sc;
  160. return _pTextFilt->Init( 0,
  161. 1,
  162. &fpsContents,
  163. pFlags );
  164. } //Init
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Member: CxxIFilter::GetChunk, public
  168. //
  169. // Synopsis: Gets the next chunk and returns chunk information in pStat
  170. //
  171. // Arguments: [pStat] -- for chunk information
  172. //
  173. // History: 07-Oct-93 AmyA Created.
  174. //
  175. //----------------------------------------------------------------------------
  176. SCODE STDMETHODCALLTYPE CxxIFilter::GetChunk( STAT_CHUNK * pStat )
  177. {
  178. SCODE sc = S_OK;
  179. CTranslateSystemExceptions translate;
  180. TRY
  181. {
  182. if (_state == FilterNextProp)
  183. {
  184. _state = FilterProp;
  185. }
  186. //
  187. // All chunks of plain text come first.
  188. //
  189. if ( _state == FilterContents )
  190. {
  191. sc = _pTextFilt->GetChunk( pStat );
  192. if ( SUCCEEDED(sc) )
  193. {
  194. pStat->locale = 0; // use the default word breaker
  195. _locale = 0;
  196. _ulLastTextChunkID = pStat->idChunk;
  197. }
  198. else if ( sc == FILTER_E_END_OF_CHUNKS )
  199. {
  200. _ulChunkID = _ulLastTextChunkID;
  201. ULONG Flags;
  202. sc = _pTextFilt->Init( 0,
  203. 1,
  204. &fpsContents,
  205. &Flags );
  206. if ( SUCCEEDED(sc) )
  207. {
  208. delete _pTextStream;
  209. _pTextStream = new CFilterTextStream (_pTextFilt);
  210. if (SUCCEEDED (_pTextStream->GetStatus()))
  211. {
  212. _cxxParse.Init( _pTextStream );
  213. _state = FilterProp;
  214. }
  215. else
  216. _state = FilterDone;
  217. }
  218. else
  219. _state = FilterDone;
  220. }
  221. }
  222. if ( _state == FilterProp && SUCCEEDED(sc) )
  223. {
  224. while ( TRUE )
  225. {
  226. if (_cxxParse.Parse())
  227. {
  228. pStat->attribute.guidPropSet = guidCPlusPlus;
  229. pStat->attribute.psProperty = _cxxParse.GetAttribute();
  230. for ( unsigned i = 0; i < _cAttrib; i++ )
  231. if ( _pAttrib[i].IsMatch( pStat->attribute ) )
  232. break;
  233. if ( _cAttrib == 0 || i < _cAttrib ) // Property should be returned
  234. {
  235. pStat->idChunk = ++_ulChunkID;
  236. pStat->breakType = CHUNK_EOS;
  237. pStat->flags = CHUNK_TEXT;
  238. pStat->locale = _locale;
  239. FILTERREGION regionSource;
  240. // what's the source of this derived property?
  241. _cxxParse.GetRegion ( regionSource );
  242. pStat->idChunkSource = regionSource.idChunk;
  243. pStat->cwcStartSource = regionSource.cwcStart;
  244. pStat->cwcLenSource = regionSource.cwcExtent;
  245. sc = S_OK;
  246. break;
  247. }
  248. }
  249. else
  250. {
  251. _state = FilterValue;
  252. break;
  253. }
  254. }
  255. }
  256. if ( _state == FilterNextValue )
  257. {
  258. _cxxParse.SkipValue();
  259. _state = FilterValue;
  260. }
  261. if ( _state == FilterValue )
  262. {
  263. while ( TRUE )
  264. {
  265. if ( _cxxParse.GetValueAttribute( pStat->attribute.psProperty ) )
  266. {
  267. pStat->attribute.guidPropSet = guidCPlusPlus;
  268. for ( unsigned i = 0; i < _cAttrib; i++ )
  269. if ( _pAttrib[i].IsMatch( pStat->attribute ) )
  270. break;
  271. if ( _cAttrib == 0 || i < _cAttrib ) // Property should be returned
  272. {
  273. pStat->flags = CHUNK_VALUE;
  274. pStat->locale = _locale;
  275. _state = FilterNextValue;
  276. sc = S_OK;
  277. break;
  278. }
  279. else
  280. _cxxParse.SkipValue();
  281. }
  282. else
  283. {
  284. _state = FilterDone;
  285. break;
  286. }
  287. }
  288. }
  289. if (_state == FilterDone || !SUCCEEDED(sc))
  290. {
  291. sc = FILTER_E_END_OF_CHUNKS;
  292. _state = FilterDone;
  293. }
  294. }
  295. CATCH(CException, e)
  296. {
  297. sc = e.GetErrorCode();
  298. }
  299. END_CATCH;
  300. return sc;
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Member: CxxIFilter::GetText, public
  305. //
  306. // Synopsis: Retrieves text from current chunk
  307. //
  308. // Arguments: [pcwcBuffer] -- count of characters in buffer
  309. // [awcBuffer] -- buffer for text
  310. //
  311. // History: 07-Oct-93 AmyA Created.
  312. //
  313. //----------------------------------------------------------------------------
  314. SCODE STDMETHODCALLTYPE CxxIFilter::GetText( ULONG * pcwcBuffer,
  315. WCHAR * awcBuffer )
  316. {
  317. if ( _state == FilterValue || _state == FilterNextValue )
  318. return FILTER_E_NO_TEXT;
  319. if ( _state == FilterContents )
  320. {
  321. return _pTextFilt->GetText( pcwcBuffer, awcBuffer );
  322. }
  323. else if ( _state == FilterProp )
  324. {
  325. if ( _cxxParse.GetTokens( pcwcBuffer, awcBuffer ))
  326. {
  327. _state = FilterNextProp;
  328. return FILTER_S_LAST_TEXT;
  329. }
  330. else
  331. return S_OK;
  332. }
  333. else if ( _state == FilterNextProp )
  334. {
  335. return FILTER_E_NO_MORE_TEXT;
  336. }
  337. else
  338. {
  339. Win4Assert ( _state == FilterDone );
  340. return FILTER_E_NO_MORE_TEXT;
  341. }
  342. }
  343. //+---------------------------------------------------------------------------
  344. //
  345. // Member: CxxIFilter::GetValue, public
  346. //
  347. // Synopsis: Not implemented for the text filter
  348. //
  349. // History: 07-Oct-93 AmyA Created.
  350. //
  351. //----------------------------------------------------------------------------
  352. SCODE STDMETHODCALLTYPE CxxIFilter::GetValue( PROPVARIANT ** ppPropValue )
  353. {
  354. if ( _state == FilterContents )
  355. return _pTextFilt->GetValue( ppPropValue );
  356. if ( _state == FilterDone )
  357. return FILTER_E_NO_MORE_VALUES;
  358. if ( _state != FilterNextValue )
  359. return FILTER_E_NO_VALUES;
  360. *ppPropValue = _cxxParse.GetValue();
  361. _state = FilterValue;
  362. if ( 0 == *ppPropValue )
  363. return FILTER_E_NO_MORE_VALUES;
  364. else
  365. return S_OK;
  366. }
  367. //+---------------------------------------------------------------------------
  368. //
  369. // Member: CxxIFilter::BindRegion, public
  370. //
  371. // Synopsis: Creates moniker or other interface for text indicated
  372. //
  373. // Arguments: [origPos] -- location of text
  374. // [riid] -- Interface Id
  375. // [ppunk] -- returned interface
  376. //
  377. // History: 07-Oct-93 AmyA Created.
  378. //
  379. //----------------------------------------------------------------------------
  380. SCODE STDMETHODCALLTYPE CxxIFilter::BindRegion( FILTERREGION origPos,
  381. REFIID riid,
  382. void ** ppunk )
  383. {
  384. return _pTextFilt->BindRegion( origPos, riid, ppunk );
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // Member: CxxIFilter::GetClassID, public
  389. //
  390. // Synopsis: Returns the class id of this class.
  391. //
  392. // Arguments: [pClassID] -- the class id
  393. //
  394. // History: 07-Oct-93 AmyA Created.
  395. //
  396. //----------------------------------------------------------------------------
  397. SCODE STDMETHODCALLTYPE CxxIFilter::GetClassID( CLSID * pClassID )
  398. {
  399. *pClassID = CLSID_CxxIFilter;
  400. return S_OK;
  401. }
  402. //+---------------------------------------------------------------------------
  403. //
  404. // Member: CxxIFilter::IsDirty, public
  405. //
  406. // Synopsis: Always returns S_FALSE since this class is read-only.
  407. //
  408. // History: 07-Oct-93 AmyA Created.
  409. //
  410. //----------------------------------------------------------------------------
  411. SCODE STDMETHODCALLTYPE CxxIFilter::IsDirty()
  412. {
  413. return S_FALSE; // Since the filter is read-only, there will never be
  414. // changes to the file.
  415. }
  416. typedef HRESULT (__stdcall * PFnLoadTextFilter)( WCHAR const * pwcPath,
  417. IFilter ** ppIFilter );
  418. PFnLoadTextFilter g_pLoadTextFilter = 0;
  419. SCODE MyLoadTextFilter( WCHAR const *pwc, IFilter **ppFilter )
  420. {
  421. if ( 0 == g_pLoadTextFilter )
  422. {
  423. // Dummy call to CIState to force query.dll to be always loaded
  424. CIState( 0, 0, 0 );
  425. g_pLoadTextFilter = (PFnLoadTextFilter) GetProcAddress( GetModuleHandle( L"query.dll" ), "LoadTextFilter" );
  426. if ( 0 == g_pLoadTextFilter )
  427. return HRESULT_FROM_WIN32( GetLastError() );
  428. }
  429. return g_pLoadTextFilter( pwc, ppFilter );
  430. }
  431. //+---------------------------------------------------------------------------
  432. //
  433. // Member: CxxIFilter::Load, public
  434. //
  435. // Synopsis: Loads the indicated file
  436. //
  437. // Arguments: [pszFileName] -- the file name
  438. // [dwMode] -- the mode to load the file in
  439. //
  440. // History: 07-Oct-93 AmyA Created.
  441. //
  442. // Notes: dwMode must be either 0 or STGM_READ.
  443. //
  444. //----------------------------------------------------------------------------
  445. SCODE STDMETHODCALLTYPE CxxIFilter::Load(LPCWSTR pszFileName, DWORD dwMode)
  446. {
  447. SCODE sc = MyLoadTextFilter( pszFileName, &_pTextFilt );
  448. if ( SUCCEEDED(sc) )
  449. {
  450. //
  451. // Load file
  452. //
  453. sc = _pTextFilt->QueryInterface( IID_IPersistFile, (void **) &_pPersFile );
  454. if ( SUCCEEDED(sc) )
  455. {
  456. sc = _pPersFile->Load( pszFileName, dwMode );
  457. }
  458. else
  459. {
  460. _pTextFilt->Release();
  461. _pTextFilt = 0;
  462. }
  463. }
  464. return sc;
  465. }
  466. //+---------------------------------------------------------------------------
  467. //
  468. // Member: CxxIFilter::Save, public
  469. //
  470. // Synopsis: Always returns E_FAIL, since the file is opened read-only
  471. //
  472. // History: 16-Jul-93 AmyA Created.
  473. //
  474. //----------------------------------------------------------------------------
  475. SCODE STDMETHODCALLTYPE CxxIFilter::Save(LPCWSTR pszFileName, BOOL fRemember)
  476. {
  477. return E_FAIL; // cannot be saved since it is read-only
  478. }
  479. //+---------------------------------------------------------------------------
  480. //
  481. // Member: CxxIFilter::SaveCompleted, public
  482. //
  483. // Synopsis: Always returns S_OK since the file is opened read-only
  484. //
  485. // History: 16-Jul-93 AmyA Created.
  486. //
  487. //----------------------------------------------------------------------------
  488. SCODE STDMETHODCALLTYPE CxxIFilter::SaveCompleted(LPCWSTR pszFileName)
  489. {
  490. return E_FAIL;
  491. }
  492. //+---------------------------------------------------------------------------
  493. //
  494. // Member: CxxIFilter::GetCurFile, public
  495. //
  496. // Synopsis: Returns a copy of the current file name
  497. //
  498. // Arguments: [ppszFileName] -- where the copied string is returned.
  499. //
  500. // History: 09-Aug-93 AmyA Created.
  501. //
  502. //----------------------------------------------------------------------------
  503. SCODE STDMETHODCALLTYPE CxxIFilter::GetCurFile(LPWSTR * ppszFileName)
  504. {
  505. return _pPersFile->GetCurFile( ppszFileName );
  506. }