| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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; |
| } |
| // #124085# CF_DIBV5 should not be possible, but keep for reading from the |
| // clipboard for being on the safe side |
| else if(CF_DIBV5 == fetc.getClipformat()) |
| { |
| // #123407# CF_DIBV5 has priority; if the try to fetch this failed, |
| // check CF_DIB availability as an alternative |
| fetc.setClipformat(CF_DIB); |
| |
| try |
| { |
| clipDataStream = getClipboardData( fetc ); |
| } |
| catch( UnsupportedFlavorException& ) |
| { |
| throw; // pass through, tried all possibilities |
| } |
| } |
| 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 if ( CF_BITMAP == aFormatEtc.getClipformat() ) |
| { |
| byteStream = WinBITMAPToOOBMP(stgmedium.hBitmap); |
| if( aFormatEtc.getTymed() == TYMED_GDI && |
| ! stgmedium.pUnkForRelease ) |
| { |
| DeleteObject(stgmedium.hBitmap); |
| } |
| } |
| else |
| { |
| clipDataToByteStream( aFormatEtc.getClipformat( ), stgmedium, byteStream ); |
| |
| // format conversion if necessary |
| // #124085# DIBV5 should not happen currently, but keep as a hint here |
| if(CF_DIBV5 == aFormatEtc.getClipformat() || 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; |
| } |
| |