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.org",          L"Title" },
60     { PKEY_Author,         L"OpenOffice.org",          L"Author" },
61     { PKEY_Subject,        L"OpenOffice.org",          L"Subject" },
62     { PKEY_Keywords,       L"OpenOffice.org",          L"Keyword" },
63     { PKEY_Comment,        L"OpenOffice.org",          L"Comments" },
64 };
65 
66 size_t gPropertyMapTableSize = sizeof(g_rgPROPERTYMAP)/sizeof(g_rgPROPERTYMAP[0]);
67 
68 //----------------------------
69 //
70 //----------------------------
71 
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 
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 //-----------------------------
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 //----------------------------
131 ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef( void )
132 {
133 	return InterlockedIncrement( &m_RefCnt );
134 }
135 
136 //----------------------------
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 //-----------------------------
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 //-----------------------------
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 //-----------------------------
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 //-----------------------------
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 //-----------------------------
197 HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit()
198 {
199     return S_OK;
200 }
201 
202 //-----------------------------
203 // IPropertyStore
204 //-----------------------------
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 //-----------------------------
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 //-----------------------------
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 //-----------------------------
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 //-----------------------------------------------------------------------------
329 CClassFactory::CClassFactory( const CLSID& clsid ) :
330     m_RefCnt(1),
331     m_Clsid(clsid)
332 {
333     InterlockedIncrement( &g_DllRefCnt );
334 }
335 
336 //-----------------------------------------------------------------------------
337 CClassFactory::~CClassFactory()
338 {
339     InterlockedDecrement( &g_DllRefCnt );
340 }
341 
342 //-----------------------------------------------------------------------------
343 //                              IUnknown methods
344 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
361 ULONG STDMETHODCALLTYPE CClassFactory::AddRef( void )
362 {
363     return InterlockedIncrement( &m_RefCnt );
364 }
365 
366 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
418 bool CClassFactory::IsLocked()
419 {
420     return ( s_ServerLocks > 0 );
421 }
422 
423 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
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