summaryrefslogtreecommitdiff
path: root/dtrans/source/win32/dtobj/DOTransferable.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'dtrans/source/win32/dtobj/DOTransferable.cxx')
-rw-r--r--dtrans/source/win32/dtobj/DOTransferable.cxx605
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;
+}
+