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