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.

737 lines
20 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: propfilt.cxx
  7. //
  8. // Contents: Code to filter properties on files
  9. //
  10. // Classes: COLEPropertyEnum
  11. // CDocStatPropertyEnum
  12. //
  13. // History: 93-Oct-18 DwightKr Created
  14. // 94-May-23 DwightKr Converted OFS to use OLE interfaces
  15. // 95-Feb-07 KyleP Rewrote
  16. //
  17. //----------------------------------------------------------------------------
  18. #include <pch.cxx>
  19. #pragma hdrstop
  20. #include <propspec.hxx>
  21. #include <ciguid.hxx>
  22. #include <tgrow.hxx>
  23. #include "propfilt.hxx"
  24. static CFullPropSpec psAttr( guidStorage, PID_STG_ATTRIBUTES );
  25. static CFullPropSpec psSize( guidStorage, PID_STG_SIZE );
  26. //+-------------------------------------------------------------------------
  27. //
  28. // Function: CheckResult
  29. //
  30. // Synopsis: DebugOut and Throw on an error
  31. //
  32. // Arguments: [hr] -- result code to be tested
  33. // [pcError] -- debugout string for debug builds
  34. //
  35. // History 95-Dec-19 dlee created
  36. //
  37. //--------------------------------------------------------------------------
  38. static inline void CheckResult(
  39. HRESULT hr,
  40. char * pcError )
  41. {
  42. if ( !SUCCEEDED( hr ) )
  43. {
  44. ciDebugOut(( DEB_IERROR, pcError, hr ));
  45. THROW( CException( hr ) );
  46. }
  47. } //CheckResult
  48. //+-------------------------------------------------------------------------
  49. //
  50. // Member: CDocStatPropertyEnum::CDocStatPropertyEnum, public
  51. //
  52. // Synopsis: Constructor
  53. //
  54. //--------------------------------------------------------------------------
  55. CDocStatPropertyEnum::CDocStatPropertyEnum( ICiCOpenedDoc * Document )
  56. : _PropertyStorage( 0 )
  57. {
  58. //
  59. // Safely get property storage
  60. //
  61. {
  62. IPropertyStorage *PropertyStorage;
  63. HRESULT hr = Document->GetStatPropertyEnum( &PropertyStorage );
  64. CheckResult( hr, "Could not get stat property storage %x\n" );
  65. _PropertyStorage.Set( PropertyStorage );
  66. }
  67. //
  68. // Safely get property enumerator
  69. //
  70. {
  71. IEnumSTATPROPSTG *PropertyEnum;
  72. HRESULT hr = _PropertyStorage->Enum( &PropertyEnum );
  73. CheckResult( hr, "Could not get property enum %x\n" );
  74. _PropertyEnum.Set( PropertyEnum );
  75. }
  76. }
  77. //+-------------------------------------------------------------------------
  78. //
  79. // Member: CDocStatPropertyEnum::~CDocStatPropertyEnum, public
  80. //
  81. // Synopsis: Destructor
  82. //
  83. // History: 93-Nov-27 DwightKr Created
  84. //
  85. //--------------------------------------------------------------------------
  86. CDocStatPropertyEnum::~CDocStatPropertyEnum()
  87. {
  88. }
  89. //+-------------------------------------------------------------------------
  90. //
  91. // Member: CDocStatPropertyEnum::GetPropertySetLocale, public
  92. //
  93. // Synopsis: Get locale if available
  94. //
  95. // Arguments: [locale] - Locale
  96. //
  97. // Returns: HRESULT from property storage
  98. //
  99. //--------------------------------------------------------------------------
  100. HRESULT CDocStatPropertyEnum::GetPropertySetLocale(LCID & locale)
  101. {
  102. return ::GetPropertySetLocale(_PropertyStorage.GetPointer(), locale);
  103. }
  104. //+-------------------------------------------------------------------------
  105. //
  106. // Member: CDocStatPropertyEnum::CacheVariant, public
  107. //
  108. // Synopsis: Load a specfied variant into the cache
  109. //
  110. // Arguments: [propid] - PROPID specifying what to load
  111. //
  112. // Returns: HRESULT from property storage
  113. //
  114. //--------------------------------------------------------------------------
  115. HRESULT CDocStatPropertyEnum::CacheVariant( PROPID propid )
  116. {
  117. //
  118. // Set up propspec for property read
  119. //
  120. PROPSPEC prspec;
  121. prspec.ulKind = PRSPEC_PROPID;
  122. prspec.propid = propid;
  123. //
  124. // Read out the property value
  125. //
  126. PROPVARIANT var;
  127. HRESULT hr = _PropertyStorage->ReadMultiple( 1, &prspec, &var );
  128. if (!SUCCEEDED( hr )) {
  129. return hr;
  130. }
  131. //
  132. // Set up storage variant
  133. //
  134. switch ( var.vt )
  135. {
  136. case VT_I8:
  137. _varCurrent.SetI8( var.hVal );
  138. break;
  139. case VT_LPWSTR:
  140. _varCurrent.SetLPWSTR( var.pwszVal );
  141. if ( !_varCurrent.IsValid() )
  142. return E_OUTOFMEMORY;
  143. break;
  144. case VT_UI4:
  145. _varCurrent.SetUI4( var.lVal );
  146. break;
  147. case VT_FILETIME:
  148. _varCurrent.SetFILETIME( var.filetime );
  149. break;
  150. default:
  151. ciDebugOut(( DEB_IERROR, "Unknown storage type %x\n", var.vt ));
  152. break;
  153. }
  154. PropVariantClear( &var );
  155. return hr;
  156. }
  157. //+-------------------------------------------------------------------------
  158. //
  159. // Member: CDocStatPropertyEnum::Next, public
  160. //
  161. // Synopsis: Move to next property
  162. //
  163. // Arguments: [ps] -- Property Specification returned
  164. //
  165. // Returns: Property value, or 0 if end of properties.
  166. //
  167. // History: 95-Feb-07 KyleP Created
  168. //
  169. //--------------------------------------------------------------------------
  170. CStorageVariant const * CDocStatPropertyEnum::Next( CFullPropSpec & ps )
  171. {
  172. //
  173. // Get the next property in the enumeration
  174. //
  175. STATPROPSTG StatPropStg;
  176. ULONG cFetched;
  177. HRESULT hr = _PropertyEnum->Next( 1, &StatPropStg, &cFetched );
  178. //
  179. // If we failed or there were no more to fetch, then we're done
  180. //
  181. if (!SUCCEEDED( hr ) || 0 == cFetched)
  182. return 0;
  183. Win4Assert( NULL == StatPropStg.lpwstrName );
  184. //
  185. // Load the property returned by the enumeration
  186. //
  187. hr = CacheVariant( StatPropStg.propid );
  188. if (!SUCCEEDED( hr ))
  189. return 0;
  190. //
  191. // Set guid and propid for full property set
  192. //
  193. ps.SetPropSet( guidStorage );
  194. ps.SetProperty( StatPropStg.propid );
  195. //
  196. // Return the cached property
  197. //
  198. return &_varCurrent;
  199. } //Next
  200. //+-------------------------------------------------------------------------
  201. //
  202. // Member: COLEPropertySetEnum::Next, public
  203. //
  204. // Synopsis: Move to next property set
  205. //
  206. // Returns: Pointer to GUID of property set. 0 if at end of sets.
  207. //
  208. // History 95-Dec-19 dlee created
  209. //
  210. //--------------------------------------------------------------------------
  211. GUID const * COLEPropertySetEnum::Next()
  212. {
  213. if ( 0 == _xPropSetEnum.GetPointer() )
  214. return 0;
  215. // Have we exhaused the current buffer of property sets? If so, then
  216. // load up another buffer.
  217. if ( _iPropSet == _cPropSets )
  218. {
  219. _iPropSet = 0;
  220. _cPropSets = 0;
  221. HRESULT hr = _xPropSetEnum->Next( cMaxSetsCached,
  222. _aPropSets,
  223. &_cPropSets );
  224. CheckResult( hr, "PropSetEnum->Next failed hr = 0x%x\n" );
  225. }
  226. if ( _cPropSets > 0 )
  227. {
  228. _iPropSet++;
  229. return &_aPropSets[ _iPropSet - 1 ].fmtid;
  230. }
  231. else
  232. {
  233. return 0;
  234. }
  235. } //Next
  236. //+-------------------------------------------------------------------------
  237. //
  238. // Member: COLEPropertySetEnum::COLEPropertySetEnum, public
  239. //
  240. // Synopsis: Opens a storage, property set storage, and enumerator
  241. //
  242. // Arguments: [Document] -- opened document
  243. //
  244. // History 95-Dec-19 dlee created
  245. //
  246. //--------------------------------------------------------------------------
  247. COLEPropertySetEnum::COLEPropertySetEnum(
  248. ICiCOpenedDoc *Document )
  249. : _cPropSets( 0 ),
  250. _iPropSet( 0 ),
  251. _fIsStorage( FALSE )
  252. {
  253. IPropertySetStorage * pPropertySetStorage;
  254. HRESULT hr = Document->GetPropertySetEnum( &pPropertySetStorage );
  255. if ( SUCCEEDED( hr ) )
  256. {
  257. if (FILTER_S_NO_PROPSETS != hr)
  258. {
  259. _fIsStorage = TRUE;
  260. // Save away property set storage
  261. _xPropSetStg.Set( pPropertySetStorage );
  262. IEnumSTATPROPSETSTG *pPropSetEnum;
  263. hr = _xPropSetStg->Enum( &pPropSetEnum );
  264. if ( E_NOTIMPL == hr )
  265. {
  266. _fIsStorage = FALSE;
  267. _xPropSetStg.Free();
  268. }
  269. else
  270. {
  271. CheckResult( hr, "PropSetStg->Enum() failed hr = 0x%x\n" );
  272. _xPropSetEnum.Set( pPropSetEnum );
  273. }
  274. }
  275. }
  276. else
  277. {
  278. // don't raise just because it wasn't a docfile
  279. if ( STG_E_FILEALREADYEXISTS != hr )
  280. CheckResult( hr, "StgOpenStorage() failed hr = 0x%x\n" );
  281. }
  282. } //COLEPropertySetEnum
  283. //+-------------------------------------------------------------------------
  284. //
  285. // Member: COLEPropertyEnum::COLEPropertyEnum, public
  286. //
  287. // Synopsis: Constructor for class that enumerates all properties on
  288. // a docfile.
  289. //
  290. // Arguments: [Document] -- opened document
  291. //
  292. // History 95-Dec-19 dlee created
  293. //
  294. //--------------------------------------------------------------------------
  295. COLEPropertyEnum::COLEPropertyEnum( ICiCOpenedDoc * Document )
  296. : _pguidCurrent( 0 ),
  297. _PropSetEnum( Document ),
  298. _Codepage( CP_ACP ),
  299. _cValues( 0 ),
  300. _iCurrent( 0 ),
  301. _fCustomOfficePropset( FALSE )
  302. {
  303. Document->AddRef( );
  304. _xDocument.Set( Document );
  305. _pguidCurrent = _PropSetEnum.Next();
  306. END_CONSTRUCTION( COLEPropertyEnum );
  307. } //COLEPropertyEnum
  308. //+-------------------------------------------------------------------------
  309. //
  310. // Member: COLEPropertyEnum::GetPropertySetLocale, public
  311. //
  312. // Synopsis: Gets locale, if any.
  313. //
  314. // Arguments: [locale] -- locale, if any
  315. //
  316. // History 99-Mar-24 KrishnaN created
  317. //
  318. //--------------------------------------------------------------------------
  319. HRESULT COLEPropertyEnum::GetPropertySetLocale(LCID & locale)
  320. {
  321. XInterface<IPropertyStorage> xPropStorage;
  322. IPropertyStorage *pPropStg = 0;
  323. HRESULT hr = _PropSetEnum.GetPSS()->Open( FMTID_UserDefinedProperties,
  324. STGM_READ |
  325. STGM_SHARE_EXCLUSIVE,
  326. &pPropStg );
  327. if (FAILED(hr))
  328. {
  329. Win4Assert(0 == pPropStg);
  330. ciDebugOut(( DEB_IERROR, "PropSetStg->Open() failed hr = 0x%x\n", hr ));
  331. return hr;
  332. }
  333. Win4Assert( 0 != pPropStg );
  334. xPropStorage.Set( pPropStg );
  335. return ::GetPropertySetLocale(xPropStorage.GetPointer(), locale);
  336. }
  337. //+-------------------------------------------------------------------------
  338. //
  339. // Member: COLEPropertyEnum::FillCache, private
  340. //
  341. // Synopsis: Loads the next property values for the current or next
  342. // property set.
  343. //
  344. // History 95-Dec-19 dlee created
  345. //
  346. //--------------------------------------------------------------------------
  347. BOOL COLEPropertyEnum::FillCache()
  348. {
  349. do
  350. {
  351. // all out of property sets?
  352. if ( 0 == _pguidCurrent )
  353. {
  354. //
  355. // If we are to filter the custom office propertyset, then do it
  356. // after we've filtered all other properties.
  357. //
  358. if ( _fCustomOfficePropset )
  359. {
  360. _fCustomOfficePropset = FALSE;
  361. _pguidCurrent = &FMTID_UserDefinedProperties;
  362. }
  363. else
  364. {
  365. return FALSE;
  366. }
  367. }
  368. FreeCache();
  369. //
  370. // If this is the office property set, then we need to also try
  371. // to filter the office CUSTOM property set.
  372. //
  373. if ( *_pguidCurrent == FMTID_SummaryInformation )
  374. {
  375. _fCustomOfficePropset = TRUE;
  376. }
  377. // Open the property storage if not yet open
  378. if ( 0 == _xPropStorage.GetPointer() )
  379. {
  380. IPropertyStorage *pPropStg;
  381. HRESULT hr = _PropSetEnum.GetPSS()->Open( *_pguidCurrent,
  382. STGM_READ |
  383. STGM_SHARE_EXCLUSIVE,
  384. &pPropStg );
  385. //
  386. // The special second-section property set will return a
  387. // special failure code if it doesn't exist. Check for this
  388. // code and ignore the property set.
  389. // OLE returns STG_E_FILENOTFOUND and the shell returns E_FAIL
  390. //
  391. if ( ( ( E_FAIL == hr ) || ( STG_E_FILENOTFOUND == hr ) ) &&
  392. ( FMTID_UserDefinedProperties == *_pguidCurrent ) )
  393. {
  394. return FALSE;
  395. }
  396. CheckResult( hr, "PropSetStg->Open() failed hr = 0x%x\n" );
  397. Win4Assert( 0 != pPropStg );
  398. if ( 0 == pPropStg )
  399. {
  400. ciDebugOut(( DEB_WARN,
  401. "IPropertySetStorage::Open( ) returned null property set and hr = 0x%x\n",
  402. hr ));
  403. _pguidCurrent = _PropSetEnum.Next();
  404. continue;
  405. }
  406. _xPropStorage.Set( pPropStg );
  407. //
  408. // Look for codepage
  409. //
  410. PROPSPEC psCodepage = { PRSPEC_PROPID, PID_CODEPAGE };
  411. PROPVARIANT varCodepage;
  412. hr = _xPropStorage->ReadMultiple( 1, &psCodepage, &varCodepage );
  413. if ( SUCCEEDED(hr) && VT_I2 == varCodepage.vt && varCodepage.iVal != CP_WINUNICODE )
  414. _Codepage = (unsigned short) varCodepage.iVal;
  415. else
  416. _Codepage = CP_ACP;
  417. Win4Assert( 0 == _xPropEnum.GetPointer() );
  418. IEnumSTATPROPSTG *pPropEnum;
  419. hr = pPropStg->Enum( &pPropEnum );
  420. CheckResult( hr, "PropStg->Enum() failed hr = 0x%x\n" );
  421. _xPropEnum.Set( pPropEnum );
  422. }
  423. HRESULT hr = _xPropEnum->Next( cMaxValuesCached, _aSPS, &_cValues );
  424. CheckResult( hr, "PropEnum->Next failed sc = 0x%x\n" );
  425. if ( _cValues > 0 )
  426. {
  427. for ( unsigned i = 0; i < _cValues; i++ )
  428. {
  429. if ( 0 != _aSPS[i].lpwstrName)
  430. {
  431. _aPropSpec[i].ulKind = PRSPEC_LPWSTR;
  432. _aPropSpec[i].lpwstr = _aSPS[i].lpwstrName;
  433. }
  434. else
  435. {
  436. _aPropSpec[i].ulKind = PRSPEC_PROPID;
  437. _aPropSpec[i].propid = _aSPS[i].propid;
  438. }
  439. }
  440. hr = _xPropStorage->ReadMultiple( _cValues,
  441. _aPropSpec,
  442. _aPropVals );
  443. CheckResult( hr, "ReadMultiple failed sc = 0x%x\n" );
  444. //
  445. // HACK #274: Translate the Ole summary information LPSTR in LPWSTR
  446. // Makes these properties compatible with HTML filter
  447. // equivalents.
  448. //
  449. if ( FMTID_SummaryInformation == *_pguidCurrent )
  450. {
  451. for ( i = 0; i < _cValues; i++ )
  452. {
  453. if ( ( VT_LPSTR == _aPropVals[i].Type() ) &&
  454. ( 0 != _aPropVals[i].GetLPSTR() ) )
  455. {
  456. // ciDebugOut(( DEB_ITRACE, "Converting \"%s\" to Unicode\n", _aPropVals[i].GetLPSTR() ));
  457. unsigned cc = strlen( _aPropVals[i].GetLPSTR() ) + 1;
  458. XGrowable<WCHAR> xwcsProp( cc + (cc * 10 / 100) ); // 10% fluff
  459. unsigned ccT = 0;
  460. while ( 0 == ccT )
  461. {
  462. ccT = MultiByteToWideChar( _Codepage,
  463. 0, // precomposed used of the codepage supports it
  464. _aPropVals[i].GetLPSTR(),
  465. cc,
  466. xwcsProp.Get(),
  467. xwcsProp.Count() );
  468. if ( 0 == ccT )
  469. {
  470. if ( ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  471. {
  472. unsigned ccNeeded = MultiByteToWideChar( _Codepage,
  473. 0, // precomposed used of the codepage supports it
  474. _aPropVals[i].GetLPSTR(),
  475. cc,
  476. 0,
  477. 0 );
  478. Win4Assert( ccNeeded > 0 );
  479. xwcsProp.SetSize( ccNeeded );
  480. }
  481. else
  482. {
  483. ciDebugOut(( DEB_ERROR, "Error %d converting %s to codepage 0x%x\n",
  484. GetLastError(), _aPropVals[i].GetLPSTR(), _Codepage ));
  485. ccT = 0;
  486. break;
  487. }
  488. }
  489. }
  490. if ( ccT != 0 )
  491. _aPropVals[i].SetLPWSTR( xwcsProp.Get() );
  492. }
  493. }
  494. }
  495. return TRUE;
  496. }
  497. else
  498. {
  499. // move on to the next property set
  500. _xPropEnum.Acquire()->Release();
  501. _xPropStorage.Acquire()->Release();
  502. _pguidCurrent = _PropSetEnum.Next();
  503. }
  504. } while ( TRUE );
  505. Win4Assert( !"never-never code path" );
  506. return FALSE;
  507. } //FillCache
  508. //+-------------------------------------------------------------------------
  509. //
  510. // Member: COLEPropertyEnum::Next, public
  511. //
  512. // Synopsis: Moves to next property
  513. //
  514. // Arguments: [ps] -- Content index propspec returned here
  515. //
  516. // Returns: Pointer to property value. 0 if at end.
  517. //
  518. // History 95-Dec-19 dlee created
  519. //
  520. //--------------------------------------------------------------------------
  521. CStorageVariant const * COLEPropertyEnum::Next(
  522. CFullPropSpec & ps )
  523. {
  524. //
  525. // If we have exhausted the cache, then try to fill it
  526. //
  527. if ( _cValues == _iCurrent && !FillCache() ) {
  528. return 0;
  529. }
  530. //
  531. // If the document is being requested, bail out
  532. //
  533. BOOL fInUse;
  534. _xDocument->IsInUseByAnotherProcess( &fInUse );
  535. if ( fInUse )
  536. {
  537. ciDebugOut(( DEB_ITRACE, "Oplock broken while filtering OLE properties\n" ));
  538. QUIETTHROW( CException( STATUS_OPLOCK_BREAK_IN_PROGRESS ) );
  539. }
  540. //
  541. // Set up the full property spec
  542. //
  543. ps.SetPropSet( *_pguidCurrent );
  544. if ( PRSPEC_LPWSTR == _aPropSpec[_iCurrent].ulKind )
  545. ps.SetProperty( _aPropSpec[_iCurrent].lpwstr );
  546. else
  547. ps.SetProperty( _aPropSpec[_iCurrent].propid );
  548. _iCurrent++;
  549. return( (CStorageVariant const *) &_aPropVals[_iCurrent-1] );
  550. } //Next
  551. //+-------------------------------------------------------------------------
  552. //
  553. // Member: COLEPropertyEnum::FreeCache, private
  554. //
  555. // Synopsis: Frees memory for the loaded properties and their specs
  556. //
  557. // History 95-Dec-19 dlee created
  558. //
  559. //--------------------------------------------------------------------------
  560. void COLEPropertyEnum::FreeCache()
  561. {
  562. for ( unsigned i = 0; i < _cValues; i++ )
  563. {
  564. PropVariantClear( (PROPVARIANT *) (void *) ( & _aPropVals[ i ] ) );
  565. if ( PRSPEC_LPWSTR == _aPropSpec[i].ulKind )
  566. CoTaskMemFree( _aSPS[i].lpwstrName );
  567. }
  568. _iCurrent = 0;
  569. _cValues = 0;
  570. } //FreeCache
  571. //+-------------------------------------------------------------------------
  572. //
  573. // Member: GetPropertySetLocale
  574. //
  575. // Synopsis: Reads the locale, if any, from property storage
  576. //
  577. // History 99-Mar-24 KrishnaN created
  578. //
  579. //--------------------------------------------------------------------------
  580. HRESULT GetPropertySetLocale(IPropertyStorage *pPropStorage, LCID & locale)
  581. {
  582. Win4Assert(0 != pPropStorage );
  583. PROPSPEC ps;
  584. PROPVARIANT prop;
  585. ps.ulKind = PRSPEC_PROPID;
  586. ps.propid = PID_LOCALE;
  587. // Get the locale for properties
  588. HRESULT hr = pPropStorage->ReadMultiple (1,
  589. &ps,
  590. &prop);
  591. if(SUCCEEDED(hr))
  592. {
  593. if(prop.vt == VT_EMPTY)
  594. {
  595. hr = E_FAIL;
  596. }
  597. else
  598. {
  599. Win4Assert(prop.vt == VT_UI4);
  600. locale = prop.ulVal;
  601. // PropVariantClear(&prop);
  602. }
  603. }
  604. return hr;
  605. }