1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: DOTransferable.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_dtrans.hxx"
34 //------------------------------------------------------------------------
36 //------------------------------------------------------------------------
37 #include <sal/types.h>
38 #include <rtl/process.h>
40 #ifndef _DOWRAPPERTRANSFERABLE_HXX_
41 #include "DOTransferable.hxx"
43 #include "..\misc\ImplHelper.hxx"
44 #include "..\misc\WinClip.hxx"
45 #include "DTransHelper.hxx"
46 #include "..\misc\ImplHelper.hxx"
47 #include "TxtCnvtHlp.hxx"
48 #include "MimeAttrib.hxx"
49 #include "FmtFilter.hxx"
53 #if(_MSC_VER < 1300) && !defined(__MINGW32__)
58 #define STR(x) STR2(x)
59 #define PRAGMA_MSG( msg ) message( __FILE__ "(" STR(__LINE__) "): " #msg )
61 //------------------------------------------------------------------------
62 // namespace directives
63 //------------------------------------------------------------------------
69 using namespace com::sun::star::uno
;
70 using namespace com::sun::star::datatransfer
;
71 using namespace com::sun::star::io
;
72 using namespace com::sun::star::lang
;
73 using namespace com::sun::star::container
;
75 //------------------------------------------------------------------------
77 //------------------------------------------------------------------------
81 const Type CPPUTYPE_SEQINT8
= getCppuType( ( Sequence
< sal_Int8
>* )0 );
82 const Type CPPUTYPE_OUSTRING
= getCppuType( (OUString
*)0 );
85 sal_Bool
isValidFlavor( const DataFlavor
& aFlavor
)
87 return ( aFlavor
.MimeType
.getLength( ) &&
88 ( ( aFlavor
.DataType
== CPPUTYPE_SEQINT8
) ||
89 ( aFlavor
.DataType
== CPPUTYPE_OUSTRING
) ) );
95 //------------------------------------------------------------------------
97 //------------------------------------------------------------------------
99 CDOTransferable::CDOTransferable(
100 const Reference
< XMultiServiceFactory
>& ServiceManager
, IDataObjectPtr rDataObject
) :
101 m_rDataObject( rDataObject
),
102 m_SrvMgr( ServiceManager
),
103 m_DataFormatTranslator( m_SrvMgr
),
104 m_bUnicodeRegistered( sal_False
),
105 m_TxtFormatOnClipboard( CF_INVALID
)
109 //------------------------------------------------------------------------
111 //------------------------------------------------------------------------
113 Any SAL_CALL
CDOTransferable::getTransferData( const DataFlavor
& aFlavor
)
114 throw( UnsupportedFlavorException
, IOException
, RuntimeException
)
116 OSL_ASSERT( isValidFlavor( aFlavor
) );
118 MutexGuard
aGuard( m_aMutex
);
120 //------------------------------------------------
121 // convert dataflavor to formatetc
122 //------------------------------------------------
124 CFormatEtc fetc
= m_DataFormatTranslator
.getFormatEtcFromDataFlavor( aFlavor
);
125 OSL_ASSERT( CF_INVALID
!= fetc
.getClipformat() );
127 //------------------------------------------------
128 // get the data from clipboard in a byte stream
129 //------------------------------------------------
131 ByteSequence_t clipDataStream
;
135 clipDataStream
= getClipboardData( fetc
);
137 catch( UnsupportedFlavorException
& )
139 if ( m_DataFormatTranslator
.isUnicodeTextFormat( fetc
.getClipformat( ) ) &&
140 m_bUnicodeRegistered
)
142 OUString aUnicodeText
= synthesizeUnicodeText( );
143 Any aAny
= makeAny( aUnicodeText
);
147 throw; // pass through exception
150 //------------------------------------------------
151 // return the data as any
152 //------------------------------------------------
154 return byteStreamToAny( clipDataStream
, aFlavor
.DataType
);
157 //------------------------------------------------------------------------
158 // getTransferDataFlavors
159 //------------------------------------------------------------------------
161 Sequence
< DataFlavor
> SAL_CALL
CDOTransferable::getTransferDataFlavors( )
162 throw( RuntimeException
)
167 //------------------------------------------------------------------------
168 // isDataFlavorSupported
169 // returns true if we find a DataFlavor with the same MimeType and
171 //------------------------------------------------------------------------
173 sal_Bool SAL_CALL
CDOTransferable::isDataFlavorSupported( const DataFlavor
& aFlavor
)
174 throw( RuntimeException
)
176 OSL_ASSERT( isValidFlavor( aFlavor
) );
178 for ( sal_Int32 i
= 0; i
< m_FlavorList
.getLength( ); i
++ )
179 if ( compareDataFlavors( aFlavor
, m_FlavorList
[i
] ) )
185 //------------------------------------------------------------------------
187 // the list of datafalvors currently on the clipboard will be initialized
188 // only once; if the client of this Transferable will hold a reference
189 // to it und the underlying clipboard content changes, the client does
190 // possible operate on a invalid list
191 // if there is only text on the clipboard we will also offer unicode text
192 // an synthesize this format on the fly if requested, to accomplish this
193 // we save the first offered text format which we will later use for the
195 //------------------------------------------------------------------------
197 void SAL_CALL
CDOTransferable::initFlavorList( )
199 IEnumFORMATETCPtr pEnumFormatEtc
;
200 HRESULT hr
= m_rDataObject
->EnumFormatEtc( DATADIR_GET
, &pEnumFormatEtc
);
201 if ( SUCCEEDED( hr
) )
203 pEnumFormatEtc
->Reset( );
206 while ( S_FALSE
!= pEnumFormatEtc
->Next( 1, &fetc
, NULL
) )
208 // we use locales only to determine the
209 // charset if there is text on the cliboard
210 // we don't offer this format
211 if ( CF_LOCALE
== fetc
.cfFormat
)
214 DataFlavor aFlavor
= formatEtcToDataFlavor( fetc
);
216 // if text or oemtext is offered we also pretend to have unicode text
217 if ( m_DataFormatTranslator
.isOemOrAnsiTextFormat( fetc
.cfFormat
) &&
218 !m_bUnicodeRegistered
)
220 addSupportedFlavor( aFlavor
);
222 m_TxtFormatOnClipboard
= fetc
.cfFormat
;
223 m_bUnicodeRegistered
= sal_True
;
225 // register unicode text as accompany format
226 aFlavor
= formatEtcToDataFlavor(
227 m_DataFormatTranslator
.getFormatEtcForClipformat( CF_UNICODETEXT
) );
228 addSupportedFlavor( aFlavor
);
230 else if ( (CF_UNICODETEXT
== fetc
.cfFormat
) && !m_bUnicodeRegistered
)
232 addSupportedFlavor( aFlavor
);
233 m_bUnicodeRegistered
= sal_True
;
236 addSupportedFlavor( aFlavor
);
238 // see MSDN IEnumFORMATETC
239 CoTaskMemFree( fetc
.ptd
);
244 //------------------------------------------------------------------------
246 //------------------------------------------------------------------------
249 void SAL_CALL
CDOTransferable::addSupportedFlavor( const DataFlavor
& aFlavor
)
251 // we ignore all formats that couldn't be translated
252 if ( aFlavor
.MimeType
.getLength( ) )
254 OSL_ASSERT( isValidFlavor( aFlavor
) );
256 m_FlavorList
.realloc( m_FlavorList
.getLength( ) + 1 );
257 m_FlavorList
[m_FlavorList
.getLength( ) - 1] = aFlavor
;
261 //------------------------------------------------------------------------
263 //------------------------------------------------------------------------
266 DataFlavor SAL_CALL
CDOTransferable::formatEtcToDataFlavor( const FORMATETC
& aFormatEtc
)
271 // for non-unicode text format we must provid a locale to get
272 // the character-set of the text, if there is no locale on the
273 // clipboard we assume the text is in a charset appropriate for
274 // the current thread locale
275 if ( (CF_TEXT
== aFormatEtc
.cfFormat
) || (CF_OEMTEXT
== aFormatEtc
.cfFormat
) )
276 lcid
= getLocaleFromClipboard( );
278 return m_DataFormatTranslator
.getDataFlavorFromFormatEtc( aFormatEtc
, lcid
);
281 //------------------------------------------------------------------------
282 // returns the current locale on clipboard; if there is no locale on
283 // clipboard the function returns the current thread locale
284 //------------------------------------------------------------------------
286 LCID SAL_CALL
CDOTransferable::getLocaleFromClipboard( )
288 LCID lcid
= GetThreadLocale( );
292 CFormatEtc fetc
= m_DataFormatTranslator
.getFormatEtcForClipformat( CF_LOCALE
);
293 ByteSequence_t aLCIDSeq
= getClipboardData( fetc
);
294 lcid
= *(reinterpret_cast<LCID
*>( aLCIDSeq
.getArray( ) ) );
296 // because of a Win95/98 Bug; there the high word
297 // of a locale has the same value as the
298 // low word e.g. 0x07040704 that's not right
299 // correct is 0x00000704
304 // we take the default locale
310 //------------------------------------------------------------------------
311 // i think it's not necessary to call ReleaseStgMedium
312 // in case of failures because nothing should have been
314 //------------------------------------------------------------------------
316 CDOTransferable::ByteSequence_t SAL_CALL
CDOTransferable::getClipboardData( CFormatEtc
& aFormatEtc
)
319 HRESULT hr
= m_rDataObject
->GetData( aFormatEtc
, &stgmedium
);
321 // in case of failure to get a WMF metafile handle, try to get a memory block
323 ( CF_METAFILEPICT
== aFormatEtc
.getClipformat() ) &&
324 ( TYMED_MFPICT
== aFormatEtc
.getTymed() ) )
326 CFormatEtc
aTempFormat( aFormatEtc
);
327 aTempFormat
.setTymed( TYMED_HGLOBAL
);
328 hr
= m_rDataObject
->GetData( aTempFormat
, &stgmedium
);
333 OSL_ASSERT( (hr
!= E_INVALIDARG
) &&
334 (hr
!= DV_E_DVASPECT
) &&
335 (hr
!= DV_E_LINDEX
) &&
336 (hr
!= DV_E_TYMED
) );
338 if ( DV_E_FORMATETC
== hr
)
339 throw UnsupportedFlavorException( );
340 else if ( STG_E_MEDIUMFULL
== hr
)
341 throw IOException( );
343 throw RuntimeException( );
346 ByteSequence_t byteStream
;
350 if ( CF_ENHMETAFILE
== aFormatEtc
.getClipformat() )
351 byteStream
= WinENHMFPictToOOMFPict( stgmedium
.hEnhMetaFile
);
352 else if (CF_HDROP
== aFormatEtc
.getClipformat())
353 byteStream
= CF_HDROPToFileList(stgmedium
.hGlobal
);
356 clipDataToByteStream( aFormatEtc
.getClipformat( ), stgmedium
, byteStream
);
358 // format conversion if necessary
359 if ( CF_DIB
== aFormatEtc
.getClipformat() )
360 byteStream
= WinDIBToOOBMP( byteStream
);
361 else if ( CF_METAFILEPICT
== aFormatEtc
.getClipformat() )
362 byteStream
= WinMFPictToOOMFPict( byteStream
);
365 ReleaseStgMedium( &stgmedium
);
367 catch( CStgTransferHelper::CStgTransferException
& )
369 ReleaseStgMedium( &stgmedium
);
370 throw IOException( );
376 //------------------------------------------------------------------------
378 //------------------------------------------------------------------------
380 OUString SAL_CALL
CDOTransferable::synthesizeUnicodeText( )
382 ByteSequence_t aTextSequence
;
384 LCID lcid
= getLocaleFromClipboard( );
385 sal_uInt32 cpForTxtCnvt
= 0;
387 if ( CF_TEXT
== m_TxtFormatOnClipboard
)
389 fetc
= m_DataFormatTranslator
.getFormatEtcForClipformat( CF_TEXT
);
390 aTextSequence
= getClipboardData( fetc
);
392 // determine the codepage used for text conversion
393 cpForTxtCnvt
= getWinCPFromLocaleId( lcid
, LOCALE_IDEFAULTANSICODEPAGE
).toInt32( );
395 else if ( CF_OEMTEXT
== m_TxtFormatOnClipboard
)
397 fetc
= m_DataFormatTranslator
.getFormatEtcForClipformat( CF_OEMTEXT
);
398 aTextSequence
= getClipboardData( fetc
);
400 // determine the codepage used for text conversion
401 cpForTxtCnvt
= getWinCPFromLocaleId( lcid
, LOCALE_IDEFAULTCODEPAGE
).toInt32( );
404 OSL_ASSERT( sal_False
);
406 CStgTransferHelper stgTransferHelper
;
409 MultiByteToWideCharEx( cpForTxtCnvt
,
410 reinterpret_cast<char*>( aTextSequence
.getArray( ) ),
411 sal::static_int_cast
<sal_uInt32
>(-1), // Huh ?
415 CRawHGlobalPtr
ptrHGlob(stgTransferHelper
);
416 sal_Unicode
* pWChar
= reinterpret_cast<sal_Unicode
*>(ptrHGlob
.GetMemPtr());
418 return OUString(pWChar
);
421 //------------------------------------------------------------------------
423 //------------------------------------------------------------------------
425 void CDOTransferable::clipDataToByteStream( CLIPFORMAT cf
, STGMEDIUM stgmedium
, ByteSequence_t
& aByteSequence
)
427 CStgTransferHelper memTransferHelper
;
429 switch( stgmedium
.tymed
)
432 memTransferHelper
.init( stgmedium
.hGlobal
);
436 memTransferHelper
.init( stgmedium
.hMetaFilePict
);
440 memTransferHelper
.init( stgmedium
.hEnhMetaFile
);
445 #pragma PRAGMA_MSG( Has to be implemented )
450 throw UnsupportedFlavorException( );
454 int nMemSize
= memTransferHelper
.memSize( cf
);
455 aByteSequence
.realloc( nMemSize
);
456 memTransferHelper
.read( aByteSequence
.getArray( ), nMemSize
);
459 //------------------------------------------------------------------------
461 //------------------------------------------------------------------------
464 Any
CDOTransferable::byteStreamToAny( ByteSequence_t
& aByteStream
, const Type
& aRequestedDataType
)
468 if ( aRequestedDataType
== CPPUTYPE_OUSTRING
)
470 OUString str
= byteStreamToOUString( aByteStream
);
471 aAny
= makeAny( str
);
474 aAny
= makeAny( aByteStream
);
479 //------------------------------------------------------------------------
481 //------------------------------------------------------------------------
484 OUString
CDOTransferable::byteStreamToOUString( ByteSequence_t
& aByteStream
)
487 sal_Int32 nMemSize
= aByteStream
.getLength( );
489 // if there is a trailing L"\0" substract 1 from length
490 if ( 0 == aByteStream
[ aByteStream
.getLength( ) - 2 ] &&
491 0 == aByteStream
[ aByteStream
.getLength( ) - 1 ] )
492 nWChars
= static_cast< sal_Int32
>( nMemSize
/ sizeof( sal_Unicode
) ) - 1;
494 nWChars
= static_cast< sal_Int32
>( nMemSize
/ sizeof( sal_Unicode
) );
496 return OUString( reinterpret_cast< sal_Unicode
* >( aByteStream
.getArray( ) ), nWChars
);
499 //------------------------------------------------------------------------
501 //------------------------------------------------------------------------
503 sal_Bool SAL_CALL
CDOTransferable::compareDataFlavors(
504 const DataFlavor
& lhs
, const DataFlavor
& rhs
)
506 if ( !m_rXMimeCntFactory
.is( ) )
508 m_rXMimeCntFactory
= Reference
< XMimeContentTypeFactory
>( m_SrvMgr
->createInstance(
509 OUString::createFromAscii( "com.sun.star.datatransfer.MimeContentTypeFactory" ) ), UNO_QUERY
);
511 OSL_ASSERT( m_rXMimeCntFactory
.is( ) );
513 sal_Bool bRet
= sal_False
;
517 Reference
< XMimeContentType
> xLhs( m_rXMimeCntFactory
->createMimeContentType( lhs
.MimeType
) );
518 Reference
< XMimeContentType
> xRhs( m_rXMimeCntFactory
->createMimeContentType( rhs
.MimeType
) );
520 if ( cmpFullMediaType( xLhs
, xRhs
) )
522 bRet
= cmpAllContentTypeParameter( xLhs
, xRhs
);
525 catch( IllegalArgumentException
& )
527 OSL_ENSURE( sal_False
, "Invalid content type detected" );
534 //------------------------------------------------------------------------
536 //------------------------------------------------------------------------
538 sal_Bool SAL_CALL
CDOTransferable::cmpFullMediaType(
539 const Reference
< XMimeContentType
>& xLhs
, const Reference
< XMimeContentType
>& xRhs
) const
541 return xLhs
->getFullMediaType().equalsIgnoreAsciiCase( xRhs
->getFullMediaType( ) );
544 //------------------------------------------------------------------------
546 //------------------------------------------------------------------------
548 sal_Bool SAL_CALL
CDOTransferable::cmpAllContentTypeParameter(
549 const Reference
< XMimeContentType
>& xLhs
, const Reference
< XMimeContentType
>& xRhs
) const
551 Sequence
< OUString
> xLhsFlavors
= xLhs
->getParameters( );
552 Sequence
< OUString
> xRhsFlavors
= xRhs
->getParameters( );
553 sal_Bool bRet
= sal_True
;
557 if ( xLhsFlavors
.getLength( ) == xRhsFlavors
.getLength( ) )
562 for ( sal_Int32 i
= 0; i
< xLhsFlavors
.getLength( ); i
++ )
564 pLhs
= xLhs
->getParameterValue( xLhsFlavors
[i
] );
565 pRhs
= xRhs
->getParameterValue( xLhsFlavors
[i
] );
567 if ( !pLhs
.equalsIgnoreAsciiCase( pRhs
) )
577 catch( NoSuchElementException
& )
581 catch( IllegalArgumentException
& )
589 ::com::sun::star::uno::Any SAL_CALL
CDOTransferable::getData( const Sequence
< sal_Int8
>& aProcessId
)
590 throw (::com::sun::star::uno::RuntimeException
)
594 sal_uInt8
* arProcCaller
= (sal_uInt8
*)(sal_Int8
*) aProcessId
.getConstArray();
596 rtl_getGlobalProcessId(arId
);
597 if( ! memcmp( arId
, arProcCaller
,16))
599 if (m_rDataObject
.is())
601 IDataObject
* pObj
= m_rDataObject
.get();
603 retVal
.setValue( &pObj
, getCppuType((sal_uInt32
*)0));