1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_shell.hxx"
26 #include "internal/global.hxx"
27 #include "internal/PropertyHdl.hxx"
28 #include "internal/fileextensions.hxx"
29 #include "internal/metainforeader.hxx"
30 #include "internal/utilities.hxx"
31 #include "internal/config.hxx"
32
33 #include <propkey.h>
34 #include <propvarutil.h>
35
36 #include <malloc.h>
37 #include <strsafe.h>
38
39 #include "internal/stream_helper.hxx"
40
41 //---------------------------
42 // Module global
43 //---------------------------
44 long g_DllRefCnt = 0;
45 HINSTANCE g_hModule = NULL;
46
47 //
48 // Map of property keys to the locations of their value(s) in the .??? XML schema
49 //
50 struct PROPERTYMAP
51 {
52 PROPERTYKEY key;
53 PCWSTR pszXPathParent;
54 PCWSTR pszValueNodeName;
55 };
56
57 PROPERTYMAP g_rgPROPERTYMAP[] =
58 {
59 { PKEY_Title, L"OpenOffice", L"Title" },
60 { PKEY_Author, L"OpenOffice", L"Author" },
61 { PKEY_Subject, L"OpenOffice", L"Subject" },
62 { PKEY_Keywords, L"OpenOffice", L"Keyword" },
63 { PKEY_Comment, L"OpenOffice", L"Comments" },
64 };
65
66 size_t gPropertyMapTableSize = sizeof(g_rgPROPERTYMAP)/sizeof(g_rgPROPERTYMAP[0]);
67
68 //----------------------------
69 //
70 //----------------------------
71
CPropertyHdl(long nRefCnt)72 CPropertyHdl::CPropertyHdl( long nRefCnt ) :
73 m_RefCnt( nRefCnt ),
74 m_pCache( NULL )
75 {
76 OutputDebugStringFormat( "CPropertyHdl: CTOR\n" );
77 InterlockedIncrement( &g_DllRefCnt );
78 }
79
80 //----------------------------
81 //
82 //----------------------------
83
~CPropertyHdl()84 CPropertyHdl::~CPropertyHdl()
85 {
86 if ( m_pCache )
87 {
88 m_pCache->Release();
89 m_pCache = NULL;
90 }
91 InterlockedDecrement( &g_DllRefCnt );
92 }
93
94 //-----------------------------
95 // IUnknown methods
96 //-----------------------------
QueryInterface(REFIID riid,void __RPC_FAR * __RPC_FAR * ppvObject)97 HRESULT STDMETHODCALLTYPE CPropertyHdl::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
98 {
99 *ppvObject = 0;
100
101 if (IID_IUnknown == riid || IID_IPropertyStore == riid)
102 {
103 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStore)\n" );
104 IUnknown* pUnk = static_cast<IPropertyStore*>(this);
105 pUnk->AddRef();
106 *ppvObject = pUnk;
107 return S_OK;
108 }
109 else if (IID_IPropertyStoreCapabilities == riid)
110 {
111 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IPropertyStoreCapabilities)\n" );
112 IUnknown* pUnk = static_cast<IPropertyStore*>(this);
113 pUnk->AddRef();
114 *ppvObject = pUnk;
115 return S_OK;
116 }
117 else if (IID_IInitializeWithStream == riid)
118 {
119 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (IID_IInitializeWithStream)\n" );
120 IUnknown* pUnk = static_cast<IInitializeWithStream*>(this);
121 pUnk->AddRef();
122 *ppvObject = pUnk;
123 return S_OK;
124 }
125 OutputDebugStringFormat( "CPropertyHdl: QueryInterface (something different)\n" );
126
127 return E_NOINTERFACE;
128 }
129
130 //----------------------------
AddRef(void)131 ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef( void )
132 {
133 return InterlockedIncrement( &m_RefCnt );
134 }
135
136 //----------------------------
Release(void)137 ULONG STDMETHODCALLTYPE CPropertyHdl::Release( void )
138 {
139 long refcnt = InterlockedDecrement( &m_RefCnt );
140
141 if ( 0 == m_RefCnt )
142 delete this;
143
144 return refcnt;
145 }
146
147 //-----------------------------
148 // IPropertyStore
149 //-----------------------------
GetCount(DWORD * pcProps)150 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetCount( DWORD *pcProps )
151 {
152 HRESULT hr = E_UNEXPECTED;
153 if ( m_pCache && pcProps )
154 {
155 hr = m_pCache->GetCount( pcProps );
156 }
157
158 return hr;
159 }
160
161 //-----------------------------
GetAt(DWORD iProp,PROPERTYKEY * pKey)162 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetAt( DWORD iProp, PROPERTYKEY *pKey )
163 {
164 HRESULT hr = E_UNEXPECTED;
165 if ( m_pCache )
166 {
167 hr = m_pCache->GetAt( iProp, pKey );
168 }
169
170 return hr;
171 }
172
173 //-----------------------------
GetValue(REFPROPERTYKEY key,PROPVARIANT * pPropVar)174 HRESULT STDMETHODCALLTYPE CPropertyHdl::GetValue( REFPROPERTYKEY key, PROPVARIANT *pPropVar )
175 {
176 HRESULT hr = E_UNEXPECTED;
177 if ( m_pCache )
178 {
179 hr = m_pCache->GetValue( key, pPropVar );
180 }
181
182 return hr;
183 }
184
185 //-----------------------------
SetValue(REFPROPERTYKEY key,REFPROPVARIANT propVar)186 HRESULT STDMETHODCALLTYPE CPropertyHdl::SetValue( REFPROPERTYKEY key, REFPROPVARIANT propVar )
187 {
188 HRESULT hr = E_UNEXPECTED;
189 if ( m_pCache )
190 {
191 hr = STG_E_ACCESSDENIED;
192 }
193 return hr;
194 }
195
196 //-----------------------------
Commit()197 HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit()
198 {
199 return S_OK;
200 }
201
202 //-----------------------------
203 // IPropertyStore
204 //-----------------------------
IsPropertyWritable(REFPROPERTYKEY key)205 HRESULT STDMETHODCALLTYPE CPropertyHdl::IsPropertyWritable( REFPROPERTYKEY key )
206 {
207 // We start with read only properties only
208 return S_FALSE;
209 }
210
211 //-----------------------------
212 // IInitializeWithStream
213 //-----------------------------
Initialize(IStream * pStream,DWORD grfMode)214 HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfMode )
215 {
216 if ( grfMode & STGM_READWRITE )
217 return STG_E_ACCESSDENIED;
218
219 if ( !m_pCache )
220 {
221 #ifdef __MINGW32__
222 if ( FAILED( PSCreateMemoryPropertyStore( IID_IPropertyStoreCache, reinterpret_cast<void**>(&m_pCache) ) ) )
223 #else
224 if ( FAILED( PSCreateMemoryPropertyStore( IID_PPV_ARGS( &m_pCache ) ) ) )
225 #endif
226 OutputDebugStringFormat( "CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" );
227
228 zlib_filefunc_def z_filefunc;
229 pStream = PrepareIStream( pStream, z_filefunc );
230
231 CMetaInfoReader *pMetaInfoReader = NULL;
232
233 try
234 {
235 pMetaInfoReader = new CMetaInfoReader( (void*)pStream, &z_filefunc );
236 LoadProperties( pMetaInfoReader );
237 delete pMetaInfoReader;
238 }
239 catch (const std::exception& e)
240 {
241 OutputDebugStringFormat( "CPropertyHdl::Initialize: Caught exception [%s]", e.what() );
242 return E_FAIL;
243 }
244 /*
245 // load extended properties and search content
246 _LoadExtendedProperties();
247 _LoadSearchContent();
248 */
249 }
250
251 return S_OK;
252 }
253
254 //-----------------------------
LoadProperties(CMetaInfoReader * pMetaInfoReader)255 void CPropertyHdl::LoadProperties( CMetaInfoReader *pMetaInfoReader )
256 {
257 OutputDebugStringFormat( "CPropertyHdl: LoadProperties\n" );
258 PROPVARIANT propvarValues;
259
260 for ( UINT i = 0; i < (UINT)gPropertyMapTableSize; ++i )
261 {
262 PropVariantClear( &propvarValues );
263 HRESULT hr = GetItemData( pMetaInfoReader, i, &propvarValues);
264 if (hr == S_OK)
265 {
266 // coerce the value(s) to the appropriate type for the property key
267 hr = PSCoerceToCanonicalValue( g_rgPROPERTYMAP[i].key, &propvarValues );
268 if (SUCCEEDED(hr))
269 {
270 // cache the value(s) loaded
271 hr = m_pCache->SetValueAndState( g_rgPROPERTYMAP[i].key, &propvarValues, PSC_NORMAL );
272 }
273 }
274 }
275 }
276
277 //-----------------------------
GetItemData(CMetaInfoReader * pMetaInfoReader,UINT nIndex,PROPVARIANT * pVarData)278 HRESULT CPropertyHdl::GetItemData( CMetaInfoReader *pMetaInfoReader, UINT nIndex, PROPVARIANT *pVarData )
279 {
280 switch (nIndex) {
281 case 0: {
282 pVarData->vt = VT_BSTR;
283 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
284 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Title=%S.\n", pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() );
285 return S_OK;
286 }
287 case 1: {
288 pVarData->vt = VT_BSTR;
289 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
290 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Author=%S.\n", pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() );
291 return S_OK;
292 }
293 case 2: {
294 pVarData->vt = VT_BSTR;
295 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
296 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Subject=%S.\n", pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() );
297 return S_OK;
298 }
299 case 3: {
300 pVarData->vt = VT_BSTR;
301 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
302 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Keywords=%S.\n", pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() );
303 return S_OK;
304 }
305 case 4: {
306 pVarData->vt = VT_BSTR;
307 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
308 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Description=%S.\n", pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() );
309 return S_OK;
310 }
311 case 5: {
312 pVarData->vt = VT_BSTR;
313 pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
314 OutputDebugStringFormat( "CPropertyHdl::GetItemData: Pages=%S.\n", pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() );
315 return S_OK;
316 }
317 }
318
319 return S_FALSE;
320 }
321
322 //-----------------------------------------------------------------------------
323 // CClassFactory
324 //-----------------------------------------------------------------------------
325
326 long CClassFactory::s_ServerLocks = 0;
327
328 //-----------------------------------------------------------------------------
CClassFactory(const CLSID & clsid)329 CClassFactory::CClassFactory( const CLSID& clsid ) :
330 m_RefCnt(1),
331 m_Clsid(clsid)
332 {
333 InterlockedIncrement( &g_DllRefCnt );
334 }
335
336 //-----------------------------------------------------------------------------
~CClassFactory()337 CClassFactory::~CClassFactory()
338 {
339 InterlockedDecrement( &g_DllRefCnt );
340 }
341
342 //-----------------------------------------------------------------------------
343 // IUnknown methods
344 //-----------------------------------------------------------------------------
QueryInterface(REFIID riid,void __RPC_FAR * __RPC_FAR * ppvObject)345 HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject )
346 {
347 *ppvObject = 0;
348
349 if ( IID_IUnknown == riid || IID_IClassFactory == riid )
350 {
351 IUnknown* pUnk = this;
352 pUnk->AddRef();
353 *ppvObject = pUnk;
354 return S_OK;
355 }
356
357 return E_NOINTERFACE;
358 }
359
360 //-----------------------------------------------------------------------------
AddRef(void)361 ULONG STDMETHODCALLTYPE CClassFactory::AddRef( void )
362 {
363 return InterlockedIncrement( &m_RefCnt );
364 }
365
366 //-----------------------------------------------------------------------------
Release(void)367 ULONG STDMETHODCALLTYPE CClassFactory::Release( void )
368 {
369 long refcnt = InterlockedDecrement( &m_RefCnt );
370
371 if (0 == refcnt)
372 delete this;
373
374 return refcnt;
375 }
376
377 //-----------------------------------------------------------------------------
378 // IClassFactory methods
379 //-----------------------------------------------------------------------------
CreateInstance(IUnknown __RPC_FAR * pUnkOuter,REFIID riid,void __RPC_FAR * __RPC_FAR * ppvObject)380 HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(
381 IUnknown __RPC_FAR *pUnkOuter,
382 REFIID riid,
383 void __RPC_FAR *__RPC_FAR *ppvObject)
384 {
385 if ( pUnkOuter != NULL )
386 return CLASS_E_NOAGGREGATION;
387
388 IUnknown* pUnk = 0;
389
390 if ( CLSID_PROPERTY_HANDLER == m_Clsid )
391 pUnk = static_cast<IPropertyStore*>( new CPropertyHdl() );
392
393 POST_CONDITION(pUnk != 0, "Could not create COM object");
394
395 if (0 == pUnk)
396 return E_OUTOFMEMORY;
397
398 HRESULT hr = pUnk->QueryInterface( riid, ppvObject );
399
400 // if QueryInterface failed the component will destroy itself
401 pUnk->Release();
402
403 return hr;
404 }
405
406 //-----------------------------------------------------------------------------
LockServer(BOOL fLock)407 HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( BOOL fLock )
408 {
409 if ( fLock )
410 InterlockedIncrement( &s_ServerLocks );
411 else
412 InterlockedDecrement( &s_ServerLocks );
413
414 return S_OK;
415 }
416
417 //-----------------------------------------------------------------------------
IsLocked()418 bool CClassFactory::IsLocked()
419 {
420 return ( s_ServerLocks > 0 );
421 }
422
423 //-----------------------------------------------------------------------------
DllGetClassObject(REFCLSID rclsid,REFIID riid,void ** ppv)424 extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv)
425 {
426 OutputDebugStringFormat( "DllGetClassObject.\n" );
427 *ppv = 0;
428
429 if ( rclsid != CLSID_PROPERTY_HANDLER )
430 return CLASS_E_CLASSNOTAVAILABLE;
431
432 if ( (riid != IID_IUnknown) && (riid != IID_IClassFactory) )
433 return E_NOINTERFACE;
434
435 IUnknown* pUnk = new CClassFactory( rclsid );
436 if ( 0 == pUnk )
437 return E_OUTOFMEMORY;
438
439 *ppv = pUnk;
440 return S_OK;
441 }
442
443 //-----------------------------------------------------------------------------
DllCanUnloadNow(void)444 extern "C" STDAPI DllCanUnloadNow( void )
445 {
446 OutputDebugStringFormat( "DllCanUnloadNow.\n" );
447 if (CClassFactory::IsLocked() || g_DllRefCnt > 0)
448 return S_FALSE;
449
450 return S_OK;
451 }
452
453 //-----------------------------------------------------------------------------
DllMain(HINSTANCE hInst,ULONG,LPVOID)454 BOOL WINAPI DllMain( HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/ )
455 {
456 OutputDebugStringFormat( "DllMain.\n" );
457 g_hModule = hInst;
458 return TRUE;
459 }
460
461 /* vim: set noet sw=4 ts=4: */
462