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