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