bump product version to 4.1.6.2
[LibreOffice.git] / dtrans / source / win32 / dtobj / DOTransferable.cxx
blob30d887d8a1652effd25935c8516a33673c880f36
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <rtl/process.h>
23 #include "DOTransferable.hxx"
24 #include "../misc/ImplHelper.hxx"
25 #include "../misc/WinClip.hxx"
26 #include "DTransHelper.hxx"
27 #include "TxtCnvtHlp.hxx"
28 #include "MimeAttrib.hxx"
29 #include "FmtFilter.hxx"
30 #include "Fetc.hxx"
31 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
32 #include <comphelper/processfactory.hxx>
34 //------------------------------------------------------------------------
35 // namespace directives
36 //------------------------------------------------------------------------
38 using namespace std;
39 using namespace osl;
40 using namespace cppu;
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::datatransfer;
43 using namespace com::sun::star::io;
44 using namespace com::sun::star::lang;
45 using namespace com::sun::star::container;
48 //------------------------------------------------------------------------
50 //------------------------------------------------------------------------
52 namespace
54 const Type CPPUTYPE_SEQINT8 = getCppuType( ( Sequence< sal_Int8 >* )0 );
55 const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 );
57 inline
58 sal_Bool isValidFlavor( const DataFlavor& aFlavor )
60 return ( aFlavor.MimeType.getLength( ) &&
61 ( ( aFlavor.DataType == CPPUTYPE_SEQINT8 ) ||
62 ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) );
65 } // end namespace
68 //------------------------------------------------------------------------
69 // ctor
70 //------------------------------------------------------------------------
72 CDOTransferable::CDOTransferable(
73 const Reference< XComponentContext >& rxContext, IDataObjectPtr rDataObject ) :
74 m_rDataObject( rDataObject ),
75 m_xContext( rxContext ),
76 m_DataFormatTranslator( rxContext ),
77 m_bUnicodeRegistered( sal_False ),
78 m_TxtFormatOnClipboard( CF_INVALID )
82 //------------------------------------------------------------------------
84 //------------------------------------------------------------------------
86 Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor )
87 throw( UnsupportedFlavorException, IOException, RuntimeException )
89 OSL_ASSERT( isValidFlavor( aFlavor ) );
91 MutexGuard aGuard( m_aMutex );
93 //------------------------------------------------
94 // convert dataflavor to formatetc
95 //------------------------------------------------
97 CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
98 OSL_ASSERT( CF_INVALID != fetc.getClipformat() );
100 //------------------------------------------------
101 // get the data from clipboard in a byte stream
102 //------------------------------------------------
104 ByteSequence_t clipDataStream;
108 clipDataStream = getClipboardData( fetc );
110 catch( UnsupportedFlavorException& )
112 if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat( ) ) &&
113 m_bUnicodeRegistered )
115 OUString aUnicodeText = synthesizeUnicodeText( );
116 Any aAny = makeAny( aUnicodeText );
117 return aAny;
119 else
120 throw; // pass through exception
123 //------------------------------------------------
124 // return the data as any
125 //------------------------------------------------
127 return byteStreamToAny( clipDataStream, aFlavor.DataType );
130 //------------------------------------------------------------------------
131 // getTransferDataFlavors
132 //------------------------------------------------------------------------
134 Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors( )
135 throw( RuntimeException )
137 return m_FlavorList;
140 //------------------------------------------------------------------------
141 // isDataFlavorSupported
142 // returns true if we find a DataFlavor with the same MimeType and
143 // DataType
144 //------------------------------------------------------------------------
146 sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
147 throw( RuntimeException )
149 OSL_ASSERT( isValidFlavor( aFlavor ) );
151 for ( sal_Int32 i = 0; i < m_FlavorList.getLength( ); i++ )
152 if ( compareDataFlavors( aFlavor, m_FlavorList[i] ) )
153 return sal_True;
155 return sal_False;
158 //------------------------------------------------------------------------
159 // helper function
160 // the list of datafalvors currently on the clipboard will be initialized
161 // only once; if the client of this Transferable will hold a reference
162 // to it und the underlying clipboard content changes, the client does
163 // possible operate on a invalid list
164 // if there is only text on the clipboard we will also offer unicode text
165 // an synthesize this format on the fly if requested, to accomplish this
166 // we save the first offered text format which we will later use for the
167 // conversion
168 //------------------------------------------------------------------------
170 void SAL_CALL CDOTransferable::initFlavorList( )
172 IEnumFORMATETCPtr pEnumFormatEtc;
173 HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc );
174 if ( SUCCEEDED( hr ) )
176 pEnumFormatEtc->Reset( );
178 FORMATETC fetc;
179 while ( S_FALSE != pEnumFormatEtc->Next( 1, &fetc, NULL ) )
181 // we use locales only to determine the
182 // charset if there is text on the cliboard
183 // we don't offer this format
184 if ( CF_LOCALE == fetc.cfFormat )
185 continue;
187 DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
189 // if text or oemtext is offered we also pretend to have unicode text
190 if ( m_DataFormatTranslator.isOemOrAnsiTextFormat( fetc.cfFormat ) &&
191 !m_bUnicodeRegistered )
193 addSupportedFlavor( aFlavor );
195 m_TxtFormatOnClipboard = fetc.cfFormat;
196 m_bUnicodeRegistered = sal_True;
198 // register unicode text as accompany format
199 aFlavor = formatEtcToDataFlavor(
200 m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) );
201 addSupportedFlavor( aFlavor );
203 else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered )
205 addSupportedFlavor( aFlavor );
206 m_bUnicodeRegistered = sal_True;
208 else
209 addSupportedFlavor( aFlavor );
211 // see MSDN IEnumFORMATETC
212 CoTaskMemFree( fetc.ptd );
217 //------------------------------------------------------------------------
219 //------------------------------------------------------------------------
221 inline
222 void SAL_CALL CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor )
224 // we ignore all formats that couldn't be translated
225 if ( aFlavor.MimeType.getLength( ) )
227 OSL_ASSERT( isValidFlavor( aFlavor ) );
229 m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 );
230 m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor;
234 //------------------------------------------------------------------------
235 // helper function
236 //------------------------------------------------------------------------
238 //inline
239 DataFlavor SAL_CALL CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc )
241 DataFlavor aFlavor;
242 LCID lcid = 0;
244 // for non-unicode text format we must provid a locale to get
245 // the character-set of the text, if there is no locale on the
246 // clipboard we assume the text is in a charset appropriate for
247 // the current thread locale
248 if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) )
249 lcid = getLocaleFromClipboard( );
251 return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid );
254 //------------------------------------------------------------------------
255 // returns the current locale on clipboard; if there is no locale on
256 // clipboard the function returns the current thread locale
257 //------------------------------------------------------------------------
259 LCID SAL_CALL CDOTransferable::getLocaleFromClipboard( )
261 LCID lcid = GetThreadLocale( );
265 CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE );
266 ByteSequence_t aLCIDSeq = getClipboardData( fetc );
267 lcid = *(reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) ) );
269 // because of a Win95/98 Bug; there the high word
270 // of a locale has the same value as the
271 // low word e.g. 0x07040704 that's not right
272 // correct is 0x00000704
273 lcid &= 0x0000FFFF;
275 catch(...)
277 // we take the default locale
280 return lcid;
283 //------------------------------------------------------------------------
284 // i think it's not necessary to call ReleaseStgMedium
285 // in case of failures because nothing should have been
286 // allocated etc.
287 //------------------------------------------------------------------------
289 CDOTransferable::ByteSequence_t SAL_CALL CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc )
291 STGMEDIUM stgmedium;
292 HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium );
294 // in case of failure to get a WMF metafile handle, try to get a memory block
295 if( FAILED( hr ) &&
296 ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) &&
297 ( TYMED_MFPICT == aFormatEtc.getTymed() ) )
299 CFormatEtc aTempFormat( aFormatEtc );
300 aTempFormat.setTymed( TYMED_HGLOBAL );
301 hr = m_rDataObject->GetData( aTempFormat, &stgmedium );
304 if ( FAILED( hr ) )
306 OSL_ASSERT( (hr != E_INVALIDARG) &&
307 (hr != DV_E_DVASPECT) &&
308 (hr != DV_E_LINDEX) &&
309 (hr != DV_E_TYMED) );
311 if ( DV_E_FORMATETC == hr )
312 throw UnsupportedFlavorException( );
313 else if ( STG_E_MEDIUMFULL == hr )
314 throw IOException( );
315 else
316 throw RuntimeException( );
319 ByteSequence_t byteStream;
323 if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() )
324 byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile );
325 else if (CF_HDROP == aFormatEtc.getClipformat())
326 byteStream = CF_HDROPToFileList(stgmedium.hGlobal);
327 else if ( CF_BITMAP == aFormatEtc.getClipformat() )
329 byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap);
330 if( aFormatEtc.getTymed() == TYMED_GDI &&
331 ! stgmedium.pUnkForRelease )
333 DeleteObject(stgmedium.hBitmap);
336 else
338 clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream );
340 // format conversion if necessary
341 if ( CF_DIB == aFormatEtc.getClipformat() )
342 byteStream = WinDIBToOOBMP( byteStream );
343 else if ( CF_METAFILEPICT == aFormatEtc.getClipformat() )
344 byteStream = WinMFPictToOOMFPict( byteStream );
347 ReleaseStgMedium( &stgmedium );
349 catch( CStgTransferHelper::CStgTransferException& )
351 ReleaseStgMedium( &stgmedium );
352 throw IOException( );
355 return byteStream;
358 //------------------------------------------------------------------------
360 //------------------------------------------------------------------------
362 OUString SAL_CALL CDOTransferable::synthesizeUnicodeText( )
364 ByteSequence_t aTextSequence;
365 CFormatEtc fetc;
366 LCID lcid = getLocaleFromClipboard( );
367 sal_uInt32 cpForTxtCnvt = 0;
369 if ( CF_TEXT == m_TxtFormatOnClipboard )
371 fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT );
372 aTextSequence = getClipboardData( fetc );
374 // determine the codepage used for text conversion
375 cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTANSICODEPAGE ).toInt32( );
377 else if ( CF_OEMTEXT == m_TxtFormatOnClipboard )
379 fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_OEMTEXT );
380 aTextSequence = getClipboardData( fetc );
382 // determine the codepage used for text conversion
383 cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTCODEPAGE ).toInt32( );
385 else
386 OSL_ASSERT( sal_False );
388 CStgTransferHelper stgTransferHelper;
390 // convert the text
391 MultiByteToWideCharEx( cpForTxtCnvt,
392 reinterpret_cast<char*>( aTextSequence.getArray( ) ),
393 sal::static_int_cast<sal_uInt32>(-1), // Huh ?
394 stgTransferHelper,
395 sal_False);
397 CRawHGlobalPtr ptrHGlob(stgTransferHelper);
398 sal_Unicode* pWChar = reinterpret_cast<sal_Unicode*>(ptrHGlob.GetMemPtr());
400 return OUString(pWChar);
403 //------------------------------------------------------------------------
405 //------------------------------------------------------------------------
407 void CDOTransferable::clipDataToByteStream( CLIPFORMAT cf, STGMEDIUM stgmedium, ByteSequence_t& aByteSequence )
409 CStgTransferHelper memTransferHelper;
411 switch( stgmedium.tymed )
413 case TYMED_HGLOBAL:
414 memTransferHelper.init( stgmedium.hGlobal );
415 break;
417 case TYMED_MFPICT:
418 memTransferHelper.init( stgmedium.hMetaFilePict );
419 break;
421 case TYMED_ENHMF:
422 memTransferHelper.init( stgmedium.hEnhMetaFile );
423 break;
425 case TYMED_ISTREAM:
426 //TODO: Has to be implemented
427 break;
429 default:
430 throw UnsupportedFlavorException( );
431 break;
434 int nMemSize = memTransferHelper.memSize( cf );
435 aByteSequence.realloc( nMemSize );
436 memTransferHelper.read( aByteSequence.getArray( ), nMemSize );
439 //------------------------------------------------------------------------
441 //------------------------------------------------------------------------
443 inline
444 Any CDOTransferable::byteStreamToAny( ByteSequence_t& aByteStream, const Type& aRequestedDataType )
446 Any aAny;
448 if ( aRequestedDataType == CPPUTYPE_OUSTRING )
450 OUString str = byteStreamToOUString( aByteStream );
451 aAny = makeAny( str );
453 else
454 aAny = makeAny( aByteStream );
456 return aAny;
459 //------------------------------------------------------------------------
461 //------------------------------------------------------------------------
463 inline
464 OUString CDOTransferable::byteStreamToOUString( ByteSequence_t& aByteStream )
466 sal_Int32 nWChars;
467 sal_Int32 nMemSize = aByteStream.getLength( );
469 // if there is a trailing L"\0" substract 1 from length
470 if ( 0 == aByteStream[ aByteStream.getLength( ) - 2 ] &&
471 0 == aByteStream[ aByteStream.getLength( ) - 1 ] )
472 nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ) - 1;
473 else
474 nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) );
476 return OUString( reinterpret_cast< sal_Unicode* >( aByteStream.getArray( ) ), nWChars );
479 //------------------------------------------------------------------------
481 //------------------------------------------------------------------------
483 sal_Bool SAL_CALL CDOTransferable::compareDataFlavors(
484 const DataFlavor& lhs, const DataFlavor& rhs )
486 if ( !m_rXMimeCntFactory.is( ) )
488 m_rXMimeCntFactory = MimeContentTypeFactory::create( m_xContext );
491 sal_Bool bRet = sal_False;
495 Reference< XMimeContentType > xLhs( m_rXMimeCntFactory->createMimeContentType( lhs.MimeType ) );
496 Reference< XMimeContentType > xRhs( m_rXMimeCntFactory->createMimeContentType( rhs.MimeType ) );
498 if ( cmpFullMediaType( xLhs, xRhs ) )
500 bRet = cmpAllContentTypeParameter( xLhs, xRhs );
503 catch( IllegalArgumentException& )
505 OSL_FAIL( "Invalid content type detected" );
506 bRet = sal_False;
509 return bRet;
512 //------------------------------------------------------------------------
514 //------------------------------------------------------------------------
516 sal_Bool SAL_CALL CDOTransferable::cmpFullMediaType(
517 const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
519 return xLhs->getFullMediaType().equalsIgnoreAsciiCase( xRhs->getFullMediaType( ) );
522 //------------------------------------------------------------------------
524 //------------------------------------------------------------------------
526 sal_Bool SAL_CALL CDOTransferable::cmpAllContentTypeParameter(
527 const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
529 Sequence< OUString > xLhsFlavors = xLhs->getParameters( );
530 Sequence< OUString > xRhsFlavors = xRhs->getParameters( );
531 sal_Bool bRet = sal_True;
535 if ( xLhsFlavors.getLength( ) == xRhsFlavors.getLength( ) )
537 OUString pLhs;
538 OUString pRhs;
540 for ( sal_Int32 i = 0; i < xLhsFlavors.getLength( ); i++ )
542 pLhs = xLhs->getParameterValue( xLhsFlavors[i] );
543 pRhs = xRhs->getParameterValue( xLhsFlavors[i] );
545 if ( !pLhs.equalsIgnoreAsciiCase( pRhs ) )
547 bRet = sal_False;
548 break;
552 else
553 bRet = sal_False;
555 catch( NoSuchElementException& )
557 bRet = sal_False;
559 catch( IllegalArgumentException& )
561 bRet = sal_False;
564 return bRet;
567 ::com::sun::star::uno::Any SAL_CALL CDOTransferable::getData( const Sequence< sal_Int8>& aProcessId )
568 throw (::com::sun::star::uno::RuntimeException)
570 Any retVal;
572 sal_uInt8 * arProcCaller= (sal_uInt8*)(sal_Int8*) aProcessId.getConstArray();
573 sal_uInt8 arId[16];
574 rtl_getGlobalProcessId(arId);
575 if( ! memcmp( arId, arProcCaller,16))
577 if (m_rDataObject.is())
579 IDataObject* pObj= m_rDataObject.get();
580 pObj->AddRef();
581 retVal.setValue( &pObj, getCppuType((sal_uInt32*)0));
584 return retVal;
588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */