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