fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / dtrans / source / win32 / dtobj / DOTransferable.cxx
blobd8e22cb6327eda5cddac6392fbd71b43ec206b5f
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>
22 #include <osl/diagnose.h>
24 #include "DOTransferable.hxx"
25 #include "../misc/ImplHelper.hxx"
26 #include "../misc/WinClip.hxx"
27 #include "DTransHelper.hxx"
28 #include "TxtCnvtHlp.hxx"
29 #include "MimeAttrib.hxx"
30 #include "FmtFilter.hxx"
31 #include "Fetc.hxx"
32 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
33 #include <comphelper/processfactory.hxx>
35 // namespace directives
37 using namespace std;
38 using namespace osl;
39 using namespace cppu;
40 using namespace com::sun::star::uno;
41 using namespace com::sun::star::datatransfer;
42 using namespace com::sun::star::io;
43 using namespace com::sun::star::lang;
44 using namespace com::sun::star::container;
46 namespace
48 const Type CPPUTYPE_SEQINT8 = cppu::UnoType<Sequence< sal_Int8 >>::get();
49 const Type CPPUTYPE_OUSTRING = cppu::UnoType<OUString>::get();
51 inline
52 sal_Bool isValidFlavor( const DataFlavor& aFlavor )
54 return ( aFlavor.MimeType.getLength( ) &&
55 ( ( aFlavor.DataType == CPPUTYPE_SEQINT8 ) ||
56 ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) );
59 } // end namespace
61 // ctor
63 CDOTransferable::CDOTransferable(
64 const Reference< XComponentContext >& rxContext, IDataObjectPtr rDataObject ) :
65 m_rDataObject( rDataObject ),
66 m_xContext( rxContext ),
67 m_DataFormatTranslator( rxContext ),
68 m_bUnicodeRegistered( sal_False ),
69 m_TxtFormatOnClipboard( CF_INVALID )
73 Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor )
74 throw( UnsupportedFlavorException, IOException, RuntimeException )
76 OSL_ASSERT( isValidFlavor( aFlavor ) );
78 MutexGuard aGuard( m_aMutex );
80 // convert dataflavor to formatetc
82 CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor );
83 OSL_ASSERT( CF_INVALID != fetc.getClipformat() );
85 // get the data from clipboard in a byte stream
87 ByteSequence_t clipDataStream;
89 try
91 clipDataStream = getClipboardData( fetc );
93 catch( UnsupportedFlavorException& )
95 if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat( ) ) &&
96 m_bUnicodeRegistered )
98 OUString aUnicodeText = synthesizeUnicodeText( );
99 Any aAny = makeAny( aUnicodeText );
100 return aAny;
102 // #i124085# CF_DIBV5 should not be possible, but keep for reading from the
103 // clipboard for being on the safe side
104 else if(CF_DIBV5 == fetc.getClipformat())
106 // #i123407# CF_DIBV5 has priority; if the try to fetch this failed,
107 // check CF_DIB availability as an alternative
108 fetc.setClipformat(CF_DIB);
112 clipDataStream = getClipboardData( fetc );
114 catch( UnsupportedFlavorException& )
116 throw; // pass through, tried all possibilities
119 else
120 throw; // pass through exception
123 // return the data as any
125 return byteStreamToAny( clipDataStream, aFlavor.DataType );
128 // getTransferDataFlavors
130 Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors( )
131 throw( RuntimeException )
133 return m_FlavorList;
136 // isDataFlavorSupported
137 // returns true if we find a DataFlavor with the same MimeType and
138 // DataType
140 sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor )
141 throw( RuntimeException )
143 OSL_ASSERT( isValidFlavor( aFlavor ) );
145 for ( sal_Int32 i = 0; i < m_FlavorList.getLength( ); i++ )
146 if ( compareDataFlavors( aFlavor, m_FlavorList[i] ) )
147 return sal_True;
149 return sal_False;
152 // helper function
153 // the list of datafalvors currently on the clipboard will be initialized
154 // only once; if the client of this Transferable will hold a reference
155 // to it und the underlying clipboard content changes, the client does
156 // possible operate on a invalid list
157 // if there is only text on the clipboard we will also offer unicode text
158 // an synthesize this format on the fly if requested, to accomplish this
159 // we save the first offered text format which we will later use for the
160 // conversion
162 void SAL_CALL CDOTransferable::initFlavorList( )
164 IEnumFORMATETCPtr pEnumFormatEtc;
165 HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc );
166 if ( SUCCEEDED( hr ) )
168 pEnumFormatEtc->Reset( );
170 FORMATETC fetc;
171 while ( S_FALSE != pEnumFormatEtc->Next( 1, &fetc, NULL ) )
173 // we use locales only to determine the
174 // charset if there is text on the cliboard
175 // we don't offer this format
176 if ( CF_LOCALE == fetc.cfFormat )
177 continue;
179 DataFlavor aFlavor = formatEtcToDataFlavor( fetc );
181 // if text or oemtext is offered we also pretend to have unicode text
182 if ( m_DataFormatTranslator.isOemOrAnsiTextFormat( fetc.cfFormat ) &&
183 !m_bUnicodeRegistered )
185 addSupportedFlavor( aFlavor );
187 m_TxtFormatOnClipboard = fetc.cfFormat;
188 m_bUnicodeRegistered = sal_True;
190 // register unicode text as accompany format
191 aFlavor = formatEtcToDataFlavor(
192 m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) );
193 addSupportedFlavor( aFlavor );
195 else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered )
197 addSupportedFlavor( aFlavor );
198 m_bUnicodeRegistered = sal_True;
200 else
201 addSupportedFlavor( aFlavor );
203 // see MSDN IEnumFORMATETC
204 CoTaskMemFree( fetc.ptd );
209 inline
210 void SAL_CALL CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor )
212 // we ignore all formats that couldn't be translated
213 if ( aFlavor.MimeType.getLength( ) )
215 OSL_ASSERT( isValidFlavor( aFlavor ) );
217 m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 );
218 m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor;
222 // helper function
224 //inline
225 DataFlavor SAL_CALL CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc )
227 DataFlavor aFlavor;
228 LCID lcid = 0;
230 // for non-unicode text format we must provid a locale to get
231 // the character-set of the text, if there is no locale on the
232 // clipboard we assume the text is in a charset appropriate for
233 // the current thread locale
234 if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) )
235 lcid = getLocaleFromClipboard( );
237 return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid );
240 // returns the current locale on clipboard; if there is no locale on
241 // clipboard the function returns the current thread locale
243 LCID SAL_CALL CDOTransferable::getLocaleFromClipboard( )
245 LCID lcid = GetThreadLocale( );
249 CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE );
250 ByteSequence_t aLCIDSeq = getClipboardData( fetc );
251 lcid = *(reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) ) );
253 // because of a Win95/98 Bug; there the high word
254 // of a locale has the same value as the
255 // low word e.g. 0x07040704 that's not right
256 // correct is 0x00000704
257 lcid &= 0x0000FFFF;
259 catch(...)
261 // we take the default locale
264 return lcid;
267 // i think it's not necessary to call ReleaseStgMedium
268 // in case of failures because nothing should have been
269 // allocated etc.
271 CDOTransferable::ByteSequence_t SAL_CALL CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc )
273 STGMEDIUM stgmedium;
274 HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium );
276 // in case of failure to get a WMF metafile handle, try to get a memory block
277 if( FAILED( hr ) &&
278 ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) &&
279 ( TYMED_MFPICT == aFormatEtc.getTymed() ) )
281 CFormatEtc aTempFormat( aFormatEtc );
282 aTempFormat.setTymed( TYMED_HGLOBAL );
283 hr = m_rDataObject->GetData( aTempFormat, &stgmedium );
286 if ( FAILED( hr ) )
288 OSL_ASSERT( (hr != E_INVALIDARG) &&
289 (hr != DV_E_DVASPECT) &&
290 (hr != DV_E_LINDEX) &&
291 (hr != DV_E_TYMED) );
293 if ( DV_E_FORMATETC == hr )
294 throw UnsupportedFlavorException( );
295 else if ( STG_E_MEDIUMFULL == hr )
296 throw IOException( );
297 else
298 throw RuntimeException( );
301 ByteSequence_t byteStream;
305 if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() )
306 byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile );
307 else if (CF_HDROP == aFormatEtc.getClipformat())
308 byteStream = CF_HDROPToFileList(stgmedium.hGlobal);
309 else if ( CF_BITMAP == aFormatEtc.getClipformat() )
311 byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap);
312 if( aFormatEtc.getTymed() == TYMED_GDI &&
313 ! stgmedium.pUnkForRelease )
315 DeleteObject(stgmedium.hBitmap);
318 else
320 clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream );
322 // format conversion if necessary
323 // #i124085# DIBV5 should not happen currently, but keep as a hint here
324 if(CF_DIBV5 == aFormatEtc.getClipformat() || CF_DIB == aFormatEtc.getClipformat())
326 byteStream = WinDIBToOOBMP(byteStream);
328 else if(CF_METAFILEPICT == aFormatEtc.getClipformat())
330 byteStream = WinMFPictToOOMFPict(byteStream);
334 ReleaseStgMedium( &stgmedium );
336 catch( CStgTransferHelper::CStgTransferException& )
338 ReleaseStgMedium( &stgmedium );
339 throw IOException( );
342 return byteStream;
345 OUString SAL_CALL CDOTransferable::synthesizeUnicodeText( )
347 ByteSequence_t aTextSequence;
348 CFormatEtc fetc;
349 LCID lcid = getLocaleFromClipboard( );
350 sal_uInt32 cpForTxtCnvt = 0;
352 if ( CF_TEXT == m_TxtFormatOnClipboard )
354 fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT );
355 aTextSequence = getClipboardData( fetc );
357 // determine the codepage used for text conversion
358 cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTANSICODEPAGE ).toInt32( );
360 else if ( CF_OEMTEXT == m_TxtFormatOnClipboard )
362 fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_OEMTEXT );
363 aTextSequence = getClipboardData( fetc );
365 // determine the codepage used for text conversion
366 cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTCODEPAGE ).toInt32( );
368 else
369 OSL_ASSERT( sal_False );
371 CStgTransferHelper stgTransferHelper;
373 // convert the text
374 MultiByteToWideCharEx( cpForTxtCnvt,
375 reinterpret_cast<char*>( aTextSequence.getArray( ) ),
376 sal::static_int_cast<sal_uInt32>(-1), // Huh ?
377 stgTransferHelper,
378 sal_False);
380 CRawHGlobalPtr ptrHGlob(stgTransferHelper);
381 sal_Unicode* pWChar = reinterpret_cast<sal_Unicode*>(ptrHGlob.GetMemPtr());
383 return OUString(pWChar);
386 void CDOTransferable::clipDataToByteStream( CLIPFORMAT cf, STGMEDIUM stgmedium, ByteSequence_t& aByteSequence )
388 CStgTransferHelper memTransferHelper;
390 switch( stgmedium.tymed )
392 case TYMED_HGLOBAL:
393 memTransferHelper.init( stgmedium.hGlobal );
394 break;
396 case TYMED_MFPICT:
397 memTransferHelper.init( stgmedium.hMetaFilePict );
398 break;
400 case TYMED_ENHMF:
401 memTransferHelper.init( stgmedium.hEnhMetaFile );
402 break;
404 case TYMED_ISTREAM:
405 //TODO: Has to be implemented
406 break;
408 default:
409 throw UnsupportedFlavorException( );
410 break;
413 int nMemSize = memTransferHelper.memSize( cf );
414 aByteSequence.realloc( nMemSize );
415 memTransferHelper.read( aByteSequence.getArray( ), nMemSize );
418 inline
419 Any CDOTransferable::byteStreamToAny( ByteSequence_t& aByteStream, const Type& aRequestedDataType )
421 Any aAny;
423 if ( aRequestedDataType == CPPUTYPE_OUSTRING )
425 OUString str = byteStreamToOUString( aByteStream );
426 aAny = makeAny( str );
428 else
429 aAny = makeAny( aByteStream );
431 return aAny;
434 inline
435 OUString CDOTransferable::byteStreamToOUString( ByteSequence_t& aByteStream )
437 sal_Int32 nWChars;
438 sal_Int32 nMemSize = aByteStream.getLength( );
440 // if there is a trailing L"\0" subtract 1 from length
441 if ( 0 == aByteStream[ aByteStream.getLength( ) - 2 ] &&
442 0 == aByteStream[ aByteStream.getLength( ) - 1 ] )
443 nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ) - 1;
444 else
445 nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) );
447 return OUString( reinterpret_cast< sal_Unicode* >( aByteStream.getArray( ) ), nWChars );
450 sal_Bool SAL_CALL CDOTransferable::compareDataFlavors(
451 const DataFlavor& lhs, const DataFlavor& rhs )
453 if ( !m_rXMimeCntFactory.is( ) )
455 m_rXMimeCntFactory = MimeContentTypeFactory::create( m_xContext );
458 sal_Bool bRet = sal_False;
462 Reference< XMimeContentType > xLhs( m_rXMimeCntFactory->createMimeContentType( lhs.MimeType ) );
463 Reference< XMimeContentType > xRhs( m_rXMimeCntFactory->createMimeContentType( rhs.MimeType ) );
465 if ( cmpFullMediaType( xLhs, xRhs ) )
467 bRet = cmpAllContentTypeParameter( xLhs, xRhs );
470 catch( IllegalArgumentException& )
472 OSL_FAIL( "Invalid content type detected" );
473 bRet = sal_False;
476 return bRet;
479 sal_Bool SAL_CALL CDOTransferable::cmpFullMediaType(
480 const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
482 return xLhs->getFullMediaType().equalsIgnoreAsciiCase( xRhs->getFullMediaType( ) );
485 sal_Bool SAL_CALL CDOTransferable::cmpAllContentTypeParameter(
486 const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const
488 Sequence< OUString > xLhsFlavors = xLhs->getParameters( );
489 Sequence< OUString > xRhsFlavors = xRhs->getParameters( );
490 sal_Bool bRet = sal_True;
494 if ( xLhsFlavors.getLength( ) == xRhsFlavors.getLength( ) )
496 OUString pLhs;
497 OUString pRhs;
499 for ( sal_Int32 i = 0; i < xLhsFlavors.getLength( ); i++ )
501 pLhs = xLhs->getParameterValue( xLhsFlavors[i] );
502 pRhs = xRhs->getParameterValue( xLhsFlavors[i] );
504 if ( !pLhs.equalsIgnoreAsciiCase( pRhs ) )
506 bRet = sal_False;
507 break;
511 else
512 bRet = sal_False;
514 catch( NoSuchElementException& )
516 bRet = sal_False;
518 catch( IllegalArgumentException& )
520 bRet = sal_False;
523 return bRet;
526 ::com::sun::star::uno::Any SAL_CALL CDOTransferable::getData( const Sequence< sal_Int8>& aProcessId )
527 throw (::com::sun::star::uno::RuntimeException)
529 Any retVal;
531 sal_uInt8 * arProcCaller= (sal_uInt8*)(sal_Int8*) aProcessId.getConstArray();
532 sal_uInt8 arId[16];
533 rtl_getGlobalProcessId(arId);
534 if( ! memcmp( arId, arProcCaller,16))
536 if (m_rDataObject.is())
538 IDataObject* pObj= m_rDataObject.get();
539 pObj->AddRef();
540 retVal.setValue( &pObj, cppu::UnoType<sal_uInt32>::get());
543 return retVal;
546 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */