diff options
Diffstat (limited to 'dtrans/source/win32/dtobj/DOTransferable.cxx')
-rw-r--r-- | dtrans/source/win32/dtobj/DOTransferable.cxx | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/dtrans/source/win32/dtobj/DOTransferable.cxx b/dtrans/source/win32/dtobj/DOTransferable.cxx new file mode 100644 index 000000000000..951c3a69d291 --- /dev/null +++ b/dtrans/source/win32/dtobj/DOTransferable.cxx @@ -0,0 +1,605 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_dtrans.hxx" + +//------------------------------------------------------------------------ +// includes +//------------------------------------------------------------------------ +#include <sal/types.h> +#include <rtl/process.h> + +#ifndef _DOWRAPPERTRANSFERABLE_HXX_ +#include "DOTransferable.hxx" +#endif +#include "..\misc\ImplHelper.hxx" +#include "..\misc\WinClip.hxx" +#include "DTransHelper.hxx" +#include "..\misc\ImplHelper.hxx" +#include "TxtCnvtHlp.hxx" +#include "MimeAttrib.hxx" +#include "FmtFilter.hxx" +#include "Fetc.hxx" + + +#if(_MSC_VER < 1300) && !defined(__MINGW32__) +#include <olestd.h> +#endif + +#define STR2(x) #x +#define STR(x) STR2(x) +#define PRAGMA_MSG( msg ) message( __FILE__ "(" STR(__LINE__) "): " #msg ) + +//------------------------------------------------------------------------ +// namespace directives +//------------------------------------------------------------------------ + +using namespace rtl; +using namespace std; +using namespace osl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::datatransfer; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +namespace +{ + const Type CPPUTYPE_SEQINT8 = getCppuType( ( Sequence< sal_Int8 >* )0 ); + const Type CPPUTYPE_OUSTRING = getCppuType( (OUString*)0 ); + + inline + sal_Bool isValidFlavor( const DataFlavor& aFlavor ) + { + return ( aFlavor.MimeType.getLength( ) && + ( ( aFlavor.DataType == CPPUTYPE_SEQINT8 ) || + ( aFlavor.DataType == CPPUTYPE_OUSTRING ) ) ); + } + +} // end namespace + + +//------------------------------------------------------------------------ +// ctor +//------------------------------------------------------------------------ + +CDOTransferable::CDOTransferable( + const Reference< XMultiServiceFactory >& ServiceManager, IDataObjectPtr rDataObject ) : + m_rDataObject( rDataObject ), + m_SrvMgr( ServiceManager ), + m_DataFormatTranslator( m_SrvMgr ), + m_bUnicodeRegistered( sal_False ), + m_TxtFormatOnClipboard( CF_INVALID ) +{ +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor ) + throw( UnsupportedFlavorException, IOException, RuntimeException ) +{ + OSL_ASSERT( isValidFlavor( aFlavor ) ); + + MutexGuard aGuard( m_aMutex ); + + //------------------------------------------------ + // convert dataflavor to formatetc + //------------------------------------------------ + + CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcFromDataFlavor( aFlavor ); + OSL_ASSERT( CF_INVALID != fetc.getClipformat() ); + + //------------------------------------------------ + // get the data from clipboard in a byte stream + //------------------------------------------------ + + ByteSequence_t clipDataStream; + + try + { + clipDataStream = getClipboardData( fetc ); + } + catch( UnsupportedFlavorException& ) + { + if ( m_DataFormatTranslator.isUnicodeTextFormat( fetc.getClipformat( ) ) && + m_bUnicodeRegistered ) + { + OUString aUnicodeText = synthesizeUnicodeText( ); + Any aAny = makeAny( aUnicodeText ); + return aAny; + } + else + throw; // pass through exception + } + + //------------------------------------------------ + // return the data as any + //------------------------------------------------ + + return byteStreamToAny( clipDataStream, aFlavor.DataType ); +} + +//------------------------------------------------------------------------ +// getTransferDataFlavors +//------------------------------------------------------------------------ + +Sequence< DataFlavor > SAL_CALL CDOTransferable::getTransferDataFlavors( ) + throw( RuntimeException ) +{ + return m_FlavorList; +} + +//------------------------------------------------------------------------ +// isDataFlavorSupported +// returns true if we find a DataFlavor with the same MimeType and +// DataType +//------------------------------------------------------------------------ + +sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFlavor ) + throw( RuntimeException ) +{ + OSL_ASSERT( isValidFlavor( aFlavor ) ); + + for ( sal_Int32 i = 0; i < m_FlavorList.getLength( ); i++ ) + if ( compareDataFlavors( aFlavor, m_FlavorList[i] ) ) + return sal_True; + + return sal_False; +} + +//------------------------------------------------------------------------ +// helper function +// the list of datafalvors currently on the clipboard will be initialized +// only once; if the client of this Transferable will hold a reference +// to it und the underlying clipboard content changes, the client does +// possible operate on a invalid list +// if there is only text on the clipboard we will also offer unicode text +// an synthesize this format on the fly if requested, to accomplish this +// we save the first offered text format which we will later use for the +// conversion +//------------------------------------------------------------------------ + +void SAL_CALL CDOTransferable::initFlavorList( ) +{ + IEnumFORMATETCPtr pEnumFormatEtc; + HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc ); + if ( SUCCEEDED( hr ) ) + { + pEnumFormatEtc->Reset( ); + + FORMATETC fetc; + while ( S_FALSE != pEnumFormatEtc->Next( 1, &fetc, NULL ) ) + { + // we use locales only to determine the + // charset if there is text on the cliboard + // we don't offer this format + if ( CF_LOCALE == fetc.cfFormat ) + continue; + + DataFlavor aFlavor = formatEtcToDataFlavor( fetc ); + + // if text or oemtext is offered we also pretend to have unicode text + if ( m_DataFormatTranslator.isOemOrAnsiTextFormat( fetc.cfFormat ) && + !m_bUnicodeRegistered ) + { + addSupportedFlavor( aFlavor ); + + m_TxtFormatOnClipboard = fetc.cfFormat; + m_bUnicodeRegistered = sal_True; + + // register unicode text as accompany format + aFlavor = formatEtcToDataFlavor( + m_DataFormatTranslator.getFormatEtcForClipformat( CF_UNICODETEXT ) ); + addSupportedFlavor( aFlavor ); + } + else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered ) + { + addSupportedFlavor( aFlavor ); + m_bUnicodeRegistered = sal_True; + } + else + addSupportedFlavor( aFlavor ); + + // see MSDN IEnumFORMATETC + CoTaskMemFree( fetc.ptd ); + } + } +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +inline +void SAL_CALL CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor ) +{ + // we ignore all formats that couldn't be translated + if ( aFlavor.MimeType.getLength( ) ) + { + OSL_ASSERT( isValidFlavor( aFlavor ) ); + + m_FlavorList.realloc( m_FlavorList.getLength( ) + 1 ); + m_FlavorList[m_FlavorList.getLength( ) - 1] = aFlavor; + } +} + +//------------------------------------------------------------------------ +// helper function +//------------------------------------------------------------------------ + +//inline +DataFlavor SAL_CALL CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) +{ + DataFlavor aFlavor; + LCID lcid = 0; + + // for non-unicode text format we must provid a locale to get + // the character-set of the text, if there is no locale on the + // clipboard we assume the text is in a charset appropriate for + // the current thread locale + if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) ) + lcid = getLocaleFromClipboard( ); + + return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid ); +} + +//------------------------------------------------------------------------ +// returns the current locale on clipboard; if there is no locale on +// clipboard the function returns the current thread locale +//------------------------------------------------------------------------ + +LCID SAL_CALL CDOTransferable::getLocaleFromClipboard( ) +{ + LCID lcid = GetThreadLocale( ); + + try + { + CFormatEtc fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_LOCALE ); + ByteSequence_t aLCIDSeq = getClipboardData( fetc ); + lcid = *(reinterpret_cast<LCID*>( aLCIDSeq.getArray( ) ) ); + + // because of a Win95/98 Bug; there the high word + // of a locale has the same value as the + // low word e.g. 0x07040704 that's not right + // correct is 0x00000704 + lcid &= 0x0000FFFF; + } + catch(...) + { + // we take the default locale + } + + return lcid; +} + +//------------------------------------------------------------------------ +// i think it's not necessary to call ReleaseStgMedium +// in case of failures because nothing should have been +// allocated etc. +//------------------------------------------------------------------------ + +CDOTransferable::ByteSequence_t SAL_CALL CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc ) +{ + STGMEDIUM stgmedium; + HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium ); + + // in case of failure to get a WMF metafile handle, try to get a memory block + if( FAILED( hr ) && + ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) && + ( TYMED_MFPICT == aFormatEtc.getTymed() ) ) + { + CFormatEtc aTempFormat( aFormatEtc ); + aTempFormat.setTymed( TYMED_HGLOBAL ); + hr = m_rDataObject->GetData( aTempFormat, &stgmedium ); + } + + if ( FAILED( hr ) ) + { + OSL_ASSERT( (hr != E_INVALIDARG) && + (hr != DV_E_DVASPECT) && + (hr != DV_E_LINDEX) && + (hr != DV_E_TYMED) ); + + if ( DV_E_FORMATETC == hr ) + throw UnsupportedFlavorException( ); + else if ( STG_E_MEDIUMFULL == hr ) + throw IOException( ); + else + throw RuntimeException( ); + } + + ByteSequence_t byteStream; + + try + { + if ( CF_ENHMETAFILE == aFormatEtc.getClipformat() ) + byteStream = WinENHMFPictToOOMFPict( stgmedium.hEnhMetaFile ); + else if (CF_HDROP == aFormatEtc.getClipformat()) + byteStream = CF_HDROPToFileList(stgmedium.hGlobal); + else + { + clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream ); + + // format conversion if necessary + if ( CF_DIB == aFormatEtc.getClipformat() ) + byteStream = WinDIBToOOBMP( byteStream ); + else if ( CF_METAFILEPICT == aFormatEtc.getClipformat() ) + byteStream = WinMFPictToOOMFPict( byteStream ); + } + + ReleaseStgMedium( &stgmedium ); + } + catch( CStgTransferHelper::CStgTransferException& ) + { + ReleaseStgMedium( &stgmedium ); + throw IOException( ); + } + + return byteStream; +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +OUString SAL_CALL CDOTransferable::synthesizeUnicodeText( ) +{ + ByteSequence_t aTextSequence; + CFormatEtc fetc; + LCID lcid = getLocaleFromClipboard( ); + sal_uInt32 cpForTxtCnvt = 0; + + if ( CF_TEXT == m_TxtFormatOnClipboard ) + { + fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_TEXT ); + aTextSequence = getClipboardData( fetc ); + + // determine the codepage used for text conversion + cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTANSICODEPAGE ).toInt32( ); + } + else if ( CF_OEMTEXT == m_TxtFormatOnClipboard ) + { + fetc = m_DataFormatTranslator.getFormatEtcForClipformat( CF_OEMTEXT ); + aTextSequence = getClipboardData( fetc ); + + // determine the codepage used for text conversion + cpForTxtCnvt = getWinCPFromLocaleId( lcid, LOCALE_IDEFAULTCODEPAGE ).toInt32( ); + } + else + OSL_ASSERT( sal_False ); + + CStgTransferHelper stgTransferHelper; + + // convert the text + MultiByteToWideCharEx( cpForTxtCnvt, + reinterpret_cast<char*>( aTextSequence.getArray( ) ), + sal::static_int_cast<sal_uInt32>(-1), // Huh ? + stgTransferHelper, + sal_False); + + CRawHGlobalPtr ptrHGlob(stgTransferHelper); + sal_Unicode* pWChar = reinterpret_cast<sal_Unicode*>(ptrHGlob.GetMemPtr()); + + return OUString(pWChar); +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +void CDOTransferable::clipDataToByteStream( CLIPFORMAT cf, STGMEDIUM stgmedium, ByteSequence_t& aByteSequence ) +{ + CStgTransferHelper memTransferHelper; + + switch( stgmedium.tymed ) + { + case TYMED_HGLOBAL: + memTransferHelper.init( stgmedium.hGlobal ); + break; + + case TYMED_MFPICT: + memTransferHelper.init( stgmedium.hMetaFilePict ); + break; + + case TYMED_ENHMF: + memTransferHelper.init( stgmedium.hEnhMetaFile ); + break; + + case TYMED_ISTREAM: + #ifdef _MSC_VER + #pragma PRAGMA_MSG( Has to be implemented ) + #endif + break; + + default: + throw UnsupportedFlavorException( ); + break; + } + + int nMemSize = memTransferHelper.memSize( cf ); + aByteSequence.realloc( nMemSize ); + memTransferHelper.read( aByteSequence.getArray( ), nMemSize ); +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +inline +Any CDOTransferable::byteStreamToAny( ByteSequence_t& aByteStream, const Type& aRequestedDataType ) +{ + Any aAny; + + if ( aRequestedDataType == CPPUTYPE_OUSTRING ) + { + OUString str = byteStreamToOUString( aByteStream ); + aAny = makeAny( str ); + } + else + aAny = makeAny( aByteStream ); + + return aAny; +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +inline +OUString CDOTransferable::byteStreamToOUString( ByteSequence_t& aByteStream ) +{ + sal_Int32 nWChars; + sal_Int32 nMemSize = aByteStream.getLength( ); + + // if there is a trailing L"\0" substract 1 from length + if ( 0 == aByteStream[ aByteStream.getLength( ) - 2 ] && + 0 == aByteStream[ aByteStream.getLength( ) - 1 ] ) + nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ) - 1; + else + nWChars = static_cast< sal_Int32 >( nMemSize / sizeof( sal_Unicode ) ); + + return OUString( reinterpret_cast< sal_Unicode* >( aByteStream.getArray( ) ), nWChars ); +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +sal_Bool SAL_CALL CDOTransferable::compareDataFlavors( + const DataFlavor& lhs, const DataFlavor& rhs ) +{ + if ( !m_rXMimeCntFactory.is( ) ) + { + m_rXMimeCntFactory = Reference< XMimeContentTypeFactory >( m_SrvMgr->createInstance( + OUString::createFromAscii( "com.sun.star.datatransfer.MimeContentTypeFactory" ) ), UNO_QUERY ); + } + OSL_ASSERT( m_rXMimeCntFactory.is( ) ); + + sal_Bool bRet = sal_False; + + try + { + Reference< XMimeContentType > xLhs( m_rXMimeCntFactory->createMimeContentType( lhs.MimeType ) ); + Reference< XMimeContentType > xRhs( m_rXMimeCntFactory->createMimeContentType( rhs.MimeType ) ); + + if ( cmpFullMediaType( xLhs, xRhs ) ) + { + bRet = cmpAllContentTypeParameter( xLhs, xRhs ); + } + } + catch( IllegalArgumentException& ) + { + OSL_ENSURE( sal_False, "Invalid content type detected" ); + bRet = sal_False; + } + + return bRet; +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +sal_Bool SAL_CALL CDOTransferable::cmpFullMediaType( + const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const +{ + return xLhs->getFullMediaType().equalsIgnoreAsciiCase( xRhs->getFullMediaType( ) ); +} + +//------------------------------------------------------------------------ +// +//------------------------------------------------------------------------ + +sal_Bool SAL_CALL CDOTransferable::cmpAllContentTypeParameter( + const Reference< XMimeContentType >& xLhs, const Reference< XMimeContentType >& xRhs ) const +{ + Sequence< OUString > xLhsFlavors = xLhs->getParameters( ); + Sequence< OUString > xRhsFlavors = xRhs->getParameters( ); + sal_Bool bRet = sal_True; + + try + { + if ( xLhsFlavors.getLength( ) == xRhsFlavors.getLength( ) ) + { + OUString pLhs; + OUString pRhs; + + for ( sal_Int32 i = 0; i < xLhsFlavors.getLength( ); i++ ) + { + pLhs = xLhs->getParameterValue( xLhsFlavors[i] ); + pRhs = xRhs->getParameterValue( xLhsFlavors[i] ); + + if ( !pLhs.equalsIgnoreAsciiCase( pRhs ) ) + { + bRet = sal_False; + break; + } + } + } + else + bRet = sal_False; + } + catch( NoSuchElementException& ) + { + bRet = sal_False; + } + catch( IllegalArgumentException& ) + { + bRet = sal_False; + } + + return bRet; +} + +::com::sun::star::uno::Any SAL_CALL CDOTransferable::getData( const Sequence< sal_Int8>& aProcessId ) + throw (::com::sun::star::uno::RuntimeException) +{ + Any retVal; + + sal_uInt8 * arProcCaller= (sal_uInt8*)(sal_Int8*) aProcessId.getConstArray(); + sal_uInt8 arId[16]; + rtl_getGlobalProcessId(arId); + if( ! memcmp( arId, arProcCaller,16)) + { + if (m_rDataObject.is()) + { + IDataObject* pObj= m_rDataObject.get(); + pObj->AddRef(); + retVal.setValue( &pObj, getCppuType((sal_uInt32*)0)); + } + } + return retVal; +} + |