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_dtrans.hxx"
26 
27 //------------------------------------------------------------------------
28 // includes
29 //------------------------------------------------------------------------
30 #include <sal/types.h>
31 #include <rtl/process.h>
32 
33 #ifndef _DOWRAPPERTRANSFERABLE_HXX_
34 #include "DOTransferable.hxx"
35 #endif
36 #include "..\misc\ImplHelper.hxx"
37 #include "..\misc\WinClip.hxx"
38 #include "DTransHelper.hxx"
39 #include "..\misc\ImplHelper.hxx"
40 #include "TxtCnvtHlp.hxx"
41 #include "MimeAttrib.hxx"
42 #include "FmtFilter.hxx"
43 #include "Fetc.hxx"
44 
45 
46 #if(_MSC_VER < 1300) && !defined(__MINGW32__)
47 #include <olestd.h>
48 #endif
49 
50 #define STR2(x) #x
51 #define STR(x) STR2(x)
52 #define PRAGMA_MSG( msg ) message( __FILE__ "(" STR(__LINE__) "): " #msg )
53 
54 //------------------------------------------------------------------------
55 // namespace directives
56 //------------------------------------------------------------------------
57 
58 using namespace rtl;
59 using namespace std;
60 using namespace osl;
61 using namespace cppu;
62 using namespace com::sun::star::uno;
63 using namespace com::sun::star::datatransfer;
64 using namespace com::sun::star::io;
65 using namespace com::sun::star::lang;
66 using namespace com::sun::star::container;
67 
68 //------------------------------------------------------------------------
69 //
70 //------------------------------------------------------------------------
71 
72 namespace
73 {
74 	const Type CPPUTYPE_SEQINT8  = getCppuType( ( Sequence< sal_Int8 >* )0 );
75 	const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 );
76 
77 	inline
78 	sal_Bool isValidFlavor( const DataFlavor& aFlavor )
79 	{
80 		return ( aFlavor.MimeType.getLength( ) &&
81 				 ( ( aFlavor.DataType ==  CPPUTYPE_SEQINT8 ) ||
82 				 ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) );
83 	}
84 
85 } // end namespace
86 
87 
88 //------------------------------------------------------------------------
89 // ctor
90 //------------------------------------------------------------------------
91 
92 CDOTransferable::CDOTransferable(
93 	const Reference< XMultiServiceFactory >& ServiceManager, IDataObjectPtr rDataObject ) :
94 	m_rDataObject( rDataObject ),
95 	m_SrvMgr( ServiceManager ),
96 	m_DataFormatTranslator( m_SrvMgr ),
97 	m_bUnicodeRegistered( sal_False ),
98 	m_TxtFormatOnClipboard( CF_INVALID )
99 {
100 }
101 
102 //------------------------------------------------------------------------
103 //
104 //------------------------------------------------------------------------
105 
106 Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor )
107 		throw( UnsupportedFlavorException, IOException, RuntimeException )
108 {
109 	OSL_ASSERT( isValidFlavor( aFlavor ) );
110 
111 	MutexGuard aGuard( m_aMutex );
112 
113 	//------------------------------------------------
114 	// convert dataflavor to formatetc
115 	//------------------------------------------------
116 
117 	CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
118 	OSL_ASSERT( CF_INVALID != fetc.getClipformat() );
119 
120 	//------------------------------------------------
121 	//	get the data from clipboard in a byte stream
122 	//------------------------------------------------
123 
124 	ByteSequence_t clipDataStream;
125 
126 	try
127 	{
128 		clipDataStream = getClipboardData( fetc );
129 	}
130 	catch( UnsupportedFlavorException& )
131 	{
132 		if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat( ) ) &&
133 			 m_bUnicodeRegistered )
134 		{
135 			 OUString aUnicodeText = synthesizeUnicodeText( );
136 			 Any aAny = makeAny( aUnicodeText );
137 			 return aAny;
138 		}
139         else if(CF_DIBV5 == fetc.getClipformat())
140         {
141             // #123407# CF_DIBV5 has priority; if the try to fetch this failed,
142             // check CF_DIB availability as an alternative
143             fetc.setClipformat(CF_DIB);
144 
145             try
146             {
147                 clipDataStream = getClipboardData( fetc );
148             }
149             catch( UnsupportedFlavorException& )
150             {
151                 throw; // pass through, tried all possibilities
152             }
153         }
154 		else
155 			throw; // pass through exception
156 	}
157 
158 	//------------------------------------------------
159 	// return the data as any
160 	//------------------------------------------------
161 
162 	return byteStreamToAny( clipDataStream, aFlavor.DataType );
163 }
164 
165 //------------------------------------------------------------------------
166 // getTransferDataFlavors
167 //------------------------------------------------------------------------
168 
169 Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors(  )
170 	throw( RuntimeException )
171 {
172 	return m_FlavorList;
173 }
174 
175 //------------------------------------------------------------------------
176 // isDataFlavorSupported
177 // returns true if we find a DataFlavor with the same MimeType and
178 // DataType
179 //------------------------------------------------------------------------
180 
181 sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
182 	throw( RuntimeException )
183 {
184 	OSL_ASSERT( isValidFlavor( aFlavor ) );
185 
186 	for ( sal_Int32 i = 0; i < m_FlavorList.getLength( ); i++ )
187 		if ( compareDataFlavors( aFlavor, m_FlavorList[i] ) )
188 			return sal_True;
189 
190 	return sal_False;
191 }
192 
193 //------------------------------------------------------------------------
194 // helper function
195 // the list of datafalvors currently on the clipboard will be initialized
196 // only once; if the client of this Transferable will hold a reference
197 // to it und the underlying clipboard content changes, the client does
198 // possible operate on a invalid list
199 // if there is only text on the clipboard we will also offer unicode text
200 // an synthesize this format on the fly if requested, to accomplish this
201 // we save the first offered text format which we will later use for the
202 // conversion
203 //------------------------------------------------------------------------
204 
205 void SAL_CALL CDOTransferable::initFlavorList( )
206 {
207 	IEnumFORMATETCPtr pEnumFormatEtc;
208 	HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc );
209 	if ( SUCCEEDED( hr ) )
210 	{
211 		pEnumFormatEtc->Reset( );
212 
213 		FORMATETC fetc;
214 		while ( S_FALSE != pEnumFormatEtc->Next( 1, &fetc, NULL ) )
215 		{
216 			// we use locales only to determine the
217 			// charset if there is text on the cliboard
218 			// we don't offer this format
219 			if ( CF_LOCALE == fetc.cfFormat )
220 				continue;
221 
222 			DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
223 
224 			// if text or oemtext is offered we also pretend to have unicode text
225 			if ( m_DataFormatTranslator.isOemOrAnsiTextFormat( fetc.cfFormat ) &&
226 				 !m_bUnicodeRegistered )
227 			{
228 				addSupportedFlavor( aFlavor );
229 
230 				m_TxtFormatOnClipboard = fetc.cfFormat;
231 				m_bUnicodeRegistered   = sal_True;
232 
233 				// register unicode text as accompany format
234 				aFlavor = formatEtcToDataFlavor(
235 					m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) );
236 				addSupportedFlavor( aFlavor );
237 			}
238 			else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered )
239 			{
240 				addSupportedFlavor( aFlavor );
241 				m_bUnicodeRegistered = sal_True;
242 			}
243 			else
244 				addSupportedFlavor( aFlavor );
245 
246 			// see MSDN IEnumFORMATETC
247 			CoTaskMemFree( fetc.ptd );
248 		}
249 	}
250 }
251 
252 //------------------------------------------------------------------------
253 //
254 //------------------------------------------------------------------------
255 
256 inline
257 void SAL_CALL CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor )
258 {
259 	// we ignore all formats that couldn't be translated
260 	if ( aFlavor.MimeType.getLength( ) )
261 	{
262 		OSL_ASSERT( isValidFlavor( aFlavor ) );
263 
264 		m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 );
265 		m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor;
266 	}
267 }
268 
269 //------------------------------------------------------------------------
270 // helper function
271 //------------------------------------------------------------------------
272 
273 //inline
274 DataFlavor SAL_CALL CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc )
275 {
276 	DataFlavor aFlavor;
277 	LCID lcid = 0;
278 
279 	// for non-unicode text format we must provid a locale to get
280 	// the character-set of the text, if there is no locale on the
281 	// clipboard we assume the text is in a charset appropriate for
282 	// the current thread locale
283 	if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) )
284 		lcid = getLocaleFromClipboard( );
285 
286 	return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid );
287 }
288 
289 //------------------------------------------------------------------------
290 // returns the current locale on clipboard; if there is no locale on
291 // clipboard the function returns the current thread locale
292 //------------------------------------------------------------------------
293 
294 LCID SAL_CALL CDOTransferable::getLocaleFromClipboard( )
295 {
296 	LCID lcid = GetThreadLocale( );
297 
298 	try
299 	{
300 		CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE );
301 		ByteSequence_t aLCIDSeq = getClipboardData( fetc );
302 		lcid = *(reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) ) );
303 
304 		// because of a Win95/98 Bug; there the high word
305 		// of a locale has the same value as the
306 		// low word e.g. 0x07040704 that's not right
307 		// correct is 0x00000704
308 		lcid &= 0x0000FFFF;
309 	}
310 	catch(...)
311 	{
312 		// we take the default locale
313 	}
314 
315 	return lcid;
316 }
317 
318 //------------------------------------------------------------------------
319 // i think it's not necessary to call ReleaseStgMedium
320 // in case of failures because nothing should have been
321 // allocated etc.
322 //------------------------------------------------------------------------
323 
324 CDOTransferable::ByteSequence_t SAL_CALL CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc )
325 {
326 	STGMEDIUM stgmedium;
327 	HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium );
328 
329 	// in case of failure to get a WMF metafile handle, try to get a memory block
330 	if( FAILED( hr ) &&
331 	    ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) &&
332 	    ( TYMED_MFPICT == aFormatEtc.getTymed() ) )
333 	{
334         CFormatEtc aTempFormat( aFormatEtc );
335 	    aTempFormat.setTymed( TYMED_HGLOBAL );
336 	    hr = m_rDataObject->GetData( aTempFormat, &stgmedium );
337 	}
338 
339 	if ( FAILED( hr ) )
340 	{
341 		OSL_ASSERT( (hr != E_INVALIDARG) &&
342 			        (hr != DV_E_DVASPECT) &&
343 					(hr != DV_E_LINDEX) &&
344 					(hr != DV_E_TYMED) );
345 
346 		if ( DV_E_FORMATETC == hr )
347 			throw UnsupportedFlavorException( );
348 		else if ( STG_E_MEDIUMFULL == hr )
349 			throw IOException( );
350 		else
351 			throw RuntimeException( );
352 	}
353 
354 	ByteSequence_t byteStream;
355 
356 	try
357 	{
358 		if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() )
359 			byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile );
360         else if (CF_HDROP == aFormatEtc.getClipformat())
361 			byteStream = CF_HDROPToFileList(stgmedium.hGlobal);
362         else if ( CF_BITMAP == aFormatEtc.getClipformat() )
363         {
364             byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap);
365             if( aFormatEtc.getTymed() == TYMED_GDI &&
366                 ! stgmedium.pUnkForRelease )
367             {
368                 DeleteObject(stgmedium.hBitmap);
369             }
370         }
371 		else
372 		{
373 			clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream );
374 
375 			// format conversion if necessary
376 			if(CF_DIBV5 == aFormatEtc.getClipformat() || CF_DIB == aFormatEtc.getClipformat())
377             {
378 				byteStream = WinDIBToOOBMP(byteStream);
379             }
380 			else if(CF_METAFILEPICT == aFormatEtc.getClipformat())
381             {
382 				byteStream = WinMFPictToOOMFPict(byteStream);
383             }
384 		}
385 
386 		ReleaseStgMedium( &stgmedium );
387 	}
388 	catch( CStgTransferHelper::CStgTransferException& )
389 	{
390 		ReleaseStgMedium( &stgmedium );
391 		throw IOException( );
392 	}
393 
394 	return byteStream;
395 }
396 
397 //------------------------------------------------------------------------
398 //
399 //------------------------------------------------------------------------
400 
401 OUString SAL_CALL CDOTransferable::synthesizeUnicodeText( )
402 {
403 	ByteSequence_t aTextSequence;
404 	CFormatEtc	   fetc;
405 	LCID		   lcid = getLocaleFromClipboard( );
406 	sal_uInt32	   cpForTxtCnvt = 0;
407 
408 	if ( CF_TEXT == m_TxtFormatOnClipboard )
409 	{
410 		fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT );
411 		aTextSequence = getClipboardData( fetc );
412 
413 		// determine the codepage used for text conversion
414 		cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTANSICODEPAGE ).toInt32( );
415 	}
416 	else if ( CF_OEMTEXT == m_TxtFormatOnClipboard )
417 	{
418 		fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_OEMTEXT );
419 		aTextSequence = getClipboardData( fetc );
420 
421 		// determine the codepage used for text conversion
422 		cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTCODEPAGE ).toInt32( );
423 	}
424 	else
425 		OSL_ASSERT( sal_False );
426 
427 	CStgTransferHelper stgTransferHelper;
428 
429 	// convert the text
430 	MultiByteToWideCharEx( cpForTxtCnvt,
431 						   reinterpret_cast<char*>( aTextSequence.getArray( ) ),
432                            sal::static_int_cast<sal_uInt32>(-1), // Huh ?
433                            stgTransferHelper,
434                            sal_False);
435 
436 	CRawHGlobalPtr	ptrHGlob(stgTransferHelper);
437 	sal_Unicode*	pWChar = reinterpret_cast<sal_Unicode*>(ptrHGlob.GetMemPtr());
438 
439 	return OUString(pWChar);
440 }
441 
442 //------------------------------------------------------------------------
443 //
444 //------------------------------------------------------------------------
445 
446 void CDOTransferable::clipDataToByteStream( CLIPFORMAT cf, STGMEDIUM stgmedium, ByteSequence_t& aByteSequence )
447 {
448 	CStgTransferHelper memTransferHelper;
449 
450 	switch( stgmedium.tymed )
451 	{
452 	case TYMED_HGLOBAL:
453 		memTransferHelper.init( stgmedium.hGlobal );
454 		break;
455 
456 	case TYMED_MFPICT:
457 		memTransferHelper.init( stgmedium.hMetaFilePict );
458 		break;
459 
460 	case TYMED_ENHMF:
461 		memTransferHelper.init( stgmedium.hEnhMetaFile );
462 		break;
463 
464 	case TYMED_ISTREAM:
465 		#ifdef _MSC_VER
466 		#pragma PRAGMA_MSG( Has to be implemented )
467 		#endif
468 		break;
469 
470 	default:
471 		throw UnsupportedFlavorException( );
472 		break;
473 	}
474 
475 	int nMemSize = memTransferHelper.memSize( cf );
476 	aByteSequence.realloc( nMemSize );
477 	memTransferHelper.read( aByteSequence.getArray( ), nMemSize );
478 }
479 
480 //------------------------------------------------------------------------
481 //
482 //------------------------------------------------------------------------
483 
484 inline
485 Any CDOTransferable::byteStreamToAny( ByteSequence_t& aByteStream, const Type& aRequestedDataType )
486 {
487 	Any aAny;
488 
489 	if ( aRequestedDataType == CPPUTYPE_OUSTRING )
490 	{
491 		OUString str = byteStreamToOUString( aByteStream );
492 		aAny = makeAny(	str );
493 	}
494 	else
495 		aAny = makeAny( aByteStream );
496 
497 	return aAny;
498 }
499 
500 //------------------------------------------------------------------------
501 //
502 //------------------------------------------------------------------------
503 
504 inline
505 OUString CDOTransferable::byteStreamToOUString( ByteSequence_t& aByteStream )
506 {
507 	sal_Int32 nWChars;
508 	sal_Int32 nMemSize = aByteStream.getLength( );
509 
510 	// if there is a trailing L"\0" substract 1 from length
511 	if ( 0 == aByteStream[ aByteStream.getLength( ) - 2 ] &&
512 		 0 == aByteStream[ aByteStream.getLength( ) - 1 ] )
513 		nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ) - 1;
514 	else
515 		nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) );
516 
517 	return OUString( reinterpret_cast< sal_Unicode* >( aByteStream.getArray( ) ), nWChars );
518 }
519 
520 //------------------------------------------------------------------------
521 //
522 //------------------------------------------------------------------------
523 
524 sal_Bool SAL_CALL CDOTransferable::compareDataFlavors(
525 	const DataFlavor& lhs, const DataFlavor& rhs )
526 {
527 	if ( !m_rXMimeCntFactory.is( ) )
528 	{
529 		m_rXMimeCntFactory = Reference< XMimeContentTypeFactory >( m_SrvMgr->createInstance(
530 			OUString::createFromAscii( "com.sun.star.datatransfer.MimeContentTypeFactory" ) ), UNO_QUERY );
531 	}
532 	OSL_ASSERT( m_rXMimeCntFactory.is( ) );
533 
534 	sal_Bool bRet = sal_False;
535 
536 	try
537 	{
538 		Reference< XMimeContentType > xLhs( m_rXMimeCntFactory->createMimeContentType( lhs.MimeType ) );
539 		Reference< XMimeContentType > xRhs( m_rXMimeCntFactory->createMimeContentType( rhs.MimeType ) );
540 
541 		if ( cmpFullMediaType( xLhs, xRhs ) )
542 		{
543 			bRet = cmpAllContentTypeParameter( xLhs, xRhs );
544 		}
545 	}
546 	catch( IllegalArgumentException& )
547 	{
548 		OSL_ENSURE( sal_False, "Invalid content type detected" );
549 		bRet = sal_False;
550 	}
551 
552 	return bRet;
553 }
554 
555 //------------------------------------------------------------------------
556 //
557 //------------------------------------------------------------------------
558 
559 sal_Bool SAL_CALL CDOTransferable::cmpFullMediaType(
560 	const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
561 {
562 	return xLhs->getFullMediaType().equalsIgnoreAsciiCase( xRhs->getFullMediaType( ) );
563 }
564 
565 //------------------------------------------------------------------------
566 //
567 //------------------------------------------------------------------------
568 
569 sal_Bool SAL_CALL CDOTransferable::cmpAllContentTypeParameter(
570 	const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
571 {
572 	Sequence< OUString > xLhsFlavors = xLhs->getParameters( );
573 	Sequence< OUString > xRhsFlavors = xRhs->getParameters( );
574 	sal_Bool bRet = sal_True;
575 
576 	try
577 	{
578 		if ( xLhsFlavors.getLength( ) == xRhsFlavors.getLength( ) )
579 		{
580 			OUString pLhs;
581 			OUString pRhs;
582 
583 			for ( sal_Int32 i = 0; i < xLhsFlavors.getLength( ); i++ )
584 			{
585 				pLhs = xLhs->getParameterValue( xLhsFlavors[i] );
586 				pRhs = xRhs->getParameterValue( xLhsFlavors[i] );
587 
588 				if ( !pLhs.equalsIgnoreAsciiCase( pRhs ) )
589 				{
590 					bRet = sal_False;
591 					break;
592 				}
593 			}
594 		}
595 		else
596 			bRet = sal_False;
597 	}
598 	catch( NoSuchElementException& )
599 	{
600 		bRet = sal_False;
601 	}
602 	catch( IllegalArgumentException& )
603 	{
604 		bRet = sal_False;
605 	}
606 
607 	return bRet;
608 }
609 
610 ::com::sun::star::uno::Any SAL_CALL CDOTransferable::getData( const Sequence< sal_Int8>& aProcessId  )
611 		throw (::com::sun::star::uno::RuntimeException)
612 {
613 	Any retVal;
614 
615 	sal_uInt8 * arProcCaller= (sal_uInt8*)(sal_Int8*) aProcessId.getConstArray();
616 	sal_uInt8 arId[16];
617 	rtl_getGlobalProcessId(arId);
618 	if( ! memcmp( arId, arProcCaller,16))
619 	{
620 		if (m_rDataObject.is())
621 		{
622 			IDataObject* pObj= m_rDataObject.get();
623 			pObj->AddRef();
624 			retVal.setValue( &pObj, getCppuType((sal_uInt32*)0));
625 		}
626 	}
627 	return retVal;
628 }
629 
630