summaryrefslogtreecommitdiffstats
path: root/vcl/source/treelist/transfer.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /vcl/source/treelist/transfer.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/treelist/transfer.cxx')
-rw-r--r--vcl/source/treelist/transfer.cxx2227
1 files changed, 2227 insertions, 0 deletions
diff --git a/vcl/source/treelist/transfer.cxx b/vcl/source/treelist/transfer.cxx
new file mode 100644
index 000000000..4506fa2ff
--- /dev/null
+++ b/vcl/source/treelist/transfer.cxx
@@ -0,0 +1,2227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#ifdef _WIN32
+#include <prewin.h>
+#include <postwin.h>
+#include <shlobj.h>
+#endif
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/uri.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <sot/exchange.hxx>
+#include <sot/storage.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/filter/SvmReader.hxx>
+#include <vcl/filter/SvmWriter.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <sot/filelist.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <comphelper/seqstream.hxx>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+#include <com/sun/star/datatransfer/XTransferable2.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+
+#include <svl/urlbmk.hxx>
+#include <vcl/inetimg.hxx>
+#include <vcl/wmf.hxx>
+#include <vcl/imap.hxx>
+#include <vcl/transfer.hxx>
+#include <rtl/strbuf.hxx>
+#include <cstdio>
+#include <vcl/dibtools.hxx>
+#include <vcl/filter/PngImageReader.hxx>
+#include <vcl/pngwrite.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <memory>
+#include <utility>
+#include <vcl/TypeSerializer.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::datatransfer;
+using namespace ::com::sun::star::datatransfer::clipboard;
+using namespace ::com::sun::star::datatransfer::dnd;
+using namespace std::literals::string_view_literals;
+
+
+#define TOD_SIG1 0x01234567
+#define TOD_SIG2 0x89abcdef
+
+SvStream& WriteTransferableObjectDescriptor( SvStream& rOStm, const TransferableObjectDescriptor& rObjDesc )
+{
+ const sal_uInt32 nFirstPos = rOStm.Tell(), nViewAspect = rObjDesc.mnViewAspect;
+ const sal_uInt32 nSig1 = TOD_SIG1, nSig2 = TOD_SIG2;
+
+ rOStm.SeekRel( 4 );
+ WriteSvGlobalName( rOStm, rObjDesc.maClassName );
+ rOStm.WriteUInt32( nViewAspect );
+ rOStm.WriteInt32( rObjDesc.maSize.Width() );
+ rOStm.WriteInt32( rObjDesc.maSize.Height() );
+ rOStm.WriteInt32( rObjDesc.maDragStartPos.X() );
+ rOStm.WriteInt32( rObjDesc.maDragStartPos.Y() );
+ rOStm.WriteUniOrByteString( rObjDesc.maTypeName, osl_getThreadTextEncoding() );
+ rOStm.WriteUniOrByteString( rObjDesc.maDisplayName, osl_getThreadTextEncoding() );
+ rOStm.WriteUInt32( nSig1 ).WriteUInt32( nSig2 );
+
+ const sal_uInt32 nLastPos = rOStm.Tell();
+
+ rOStm.Seek( nFirstPos );
+ rOStm.WriteUInt32( nLastPos - nFirstPos );
+ rOStm.Seek( nLastPos );
+
+ return rOStm;
+}
+
+
+// the reading of the parameter is done using the special service css::datatransfer::MimeContentType,
+// a similar approach should be implemented for creation of the mimetype string;
+// for now the set of acceptable characters has to be hardcoded, in future it should be part of the service that creates the mimetype
+
+static OUString ImplGetParameterString( const TransferableObjectDescriptor& rObjDesc )
+{
+ const OUString aClassName( rObjDesc.maClassName.GetHexName() );
+ OUString aParams;
+
+ if( !aClassName.isEmpty() )
+ {
+ aParams += ";classname=\"" + aClassName + "\"";
+ }
+
+ if( !rObjDesc.maTypeName.isEmpty() )
+ {
+ aParams += ";typename=\"" + rObjDesc.maTypeName + "\"";
+ }
+
+ if( !rObjDesc.maDisplayName.isEmpty() )
+ {
+ // the display name might contain unacceptable characters, encode all of them
+ // this seems to be the only parameter currently that might contain such characters
+ static constexpr auto pToAccept = rtl::createUriCharClass(
+ u8"()<>@,;:/[]?=!#$&'*+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~. ");
+
+ aParams += ";displayname=\""
+ + rtl::Uri::encode(
+ rObjDesc.maDisplayName, pToAccept.data(), rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8)
+ + "\"";
+ }
+
+ aParams += ";viewaspect=\"" + OUString::number(rObjDesc.mnViewAspect)
+ + "\";width=\"" + OUString::number(rObjDesc.maSize.Width())
+ + "\";height=\"" + OUString::number(rObjDesc.maSize.Height())
+ + "\";posx=\"" + OUString::number(rObjDesc.maDragStartPos.X())
+ + "\";posy=\"" + OUString::number(rObjDesc.maDragStartPos.X()) + "\"";
+
+ return aParams;
+}
+
+
+static void ImplSetParameterString( TransferableObjectDescriptor& rObjDesc, const DataFlavorEx& rFlavorEx )
+{
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+
+ try
+ {
+ Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
+
+ Reference< XMimeContentType > xMimeType( xMimeFact->createMimeContentType( rFlavorEx.MimeType ) );
+
+ if( xMimeType.is() )
+ {
+ static const OUStringLiteral aClassNameString( u"classname" );
+ static const OUStringLiteral aTypeNameString( u"typename" );
+ static const OUStringLiteral aDisplayNameString( u"displayname" );
+ static const OUStringLiteral aViewAspectString( u"viewaspect" );
+ static const OUStringLiteral aWidthString( u"width" );
+ static const OUStringLiteral aHeightString( u"height" );
+ static const OUStringLiteral aPosXString( u"posx" );
+ static const OUStringLiteral aPosYString( u"posy" );
+
+ if( xMimeType->hasParameter( aClassNameString ) )
+ {
+ rObjDesc.maClassName.MakeId( xMimeType->getParameterValue( aClassNameString ) );
+ }
+
+ if( xMimeType->hasParameter( aTypeNameString ) )
+ {
+ rObjDesc.maTypeName = xMimeType->getParameterValue( aTypeNameString );
+ }
+
+ if( xMimeType->hasParameter( aDisplayNameString ) )
+ {
+ // the display name might contain unacceptable characters, in this case they should be encoded
+ // this seems to be the only parameter currently that might contain such characters
+ rObjDesc.maDisplayName = ::rtl::Uri::decode( xMimeType->getParameterValue( aDisplayNameString ), rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
+ }
+
+ if( xMimeType->hasParameter( aViewAspectString ) )
+ {
+ rObjDesc.mnViewAspect = static_cast< sal_uInt16 >( xMimeType->getParameterValue( aViewAspectString ).toInt32() );
+ }
+
+ if( xMimeType->hasParameter( aWidthString ) )
+ {
+ rObjDesc.maSize.setWidth( xMimeType->getParameterValue( aWidthString ).toInt32() );
+ }
+
+ if( xMimeType->hasParameter( aHeightString ) )
+ {
+ rObjDesc.maSize.setHeight( xMimeType->getParameterValue( aHeightString ).toInt32() );
+ }
+
+ if( xMimeType->hasParameter( aPosXString ) )
+ {
+ rObjDesc.maDragStartPos.setX( xMimeType->getParameterValue( aPosXString ).toInt32() );
+ }
+
+ if( xMimeType->hasParameter( aPosYString ) )
+ {
+ rObjDesc.maDragStartPos.setY( xMimeType->getParameterValue( aPosYString ).toInt32() );
+ }
+ }
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+
+TransferableHelper::TerminateListener::TerminateListener( TransferableHelper& rTransferableHelper ) :
+ mrParent( rTransferableHelper )
+{
+}
+
+
+TransferableHelper::TerminateListener::~TerminateListener()
+{
+}
+
+
+void SAL_CALL TransferableHelper::TerminateListener::disposing( const EventObject& )
+{
+}
+
+
+void SAL_CALL TransferableHelper::TerminateListener::queryTermination( const EventObject& )
+{
+}
+
+
+void SAL_CALL TransferableHelper::TerminateListener::notifyTermination( const EventObject& )
+{
+ mrParent.ImplFlush();
+}
+
+OUString SAL_CALL TransferableHelper::TerminateListener::getImplementationName()
+{
+ return "com.sun.star.comp.svt.TransferableHelperTerminateListener";
+}
+
+sal_Bool SAL_CALL TransferableHelper::TerminateListener::supportsService(const OUString& /*rServiceName*/)
+{
+ return false;
+}
+
+css::uno::Sequence<OUString> TransferableHelper::TerminateListener::getSupportedServiceNames()
+{
+ return {};
+}
+
+TransferableHelper::~TransferableHelper()
+{
+ css::uno::Reference<css::frame::XTerminateListener> listener;
+ {
+ const SolarMutexGuard aGuard;
+ std::swap(listener, mxTerminateListener);
+ }
+ if (listener.is()) {
+ Desktop::create(comphelper::getProcessComponentContext())->removeTerminateListener(
+ listener);
+ }
+}
+
+Any SAL_CALL TransferableHelper::getTransferData( const DataFlavor& rFlavor )
+{
+ return getTransferData2(rFlavor, OUString());
+}
+
+Any SAL_CALL TransferableHelper::getTransferData2( const DataFlavor& rFlavor, const OUString& rDestDoc )
+{
+ if( !maAny.hasValue() || maFormats.empty() || ( maLastFormat != rFlavor.MimeType ) )
+ {
+ const SolarMutexGuard aGuard;
+
+ maLastFormat = rFlavor.MimeType;
+ maAny = Any();
+
+ try
+ {
+ DataFlavor aSubstFlavor;
+ bool bDone = false;
+
+ // add formats if not already done
+ if (maFormats.empty())
+ AddSupportedFormats();
+
+ // check alien formats first and try to get a substitution format
+ if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aSubstFlavor ) &&
+ TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) )
+ {
+ GetData(aSubstFlavor, rDestDoc);
+ bDone = maAny.hasValue();
+ }
+ else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor )
+ && TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor )
+ && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BITMAP, aSubstFlavor))
+ {
+ GetData(aSubstFlavor, rDestDoc);
+ bDone = true;
+ }
+ else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
+ TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
+ SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
+ {
+ GetData(aSubstFlavor, rDestDoc);
+
+ if( maAny.hasValue() )
+ {
+ Sequence< sal_Int8 > aSeq;
+
+ if( maAny >>= aSeq )
+ {
+ GDIMetaFile aMtf;
+ {
+ SvMemoryStream aSrcStm( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC );
+ SvmReader aReader( aSrcStm );
+ aReader.Read( aMtf );
+ }
+
+ Graphic aGraphic( aMtf );
+ SvMemoryStream aDstStm( 65535, 65535 );
+
+ if( GraphicConverter::Export( aDstStm, aGraphic, ConvertDataFormat::EMF ) == ERRCODE_NONE )
+ {
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
+ aDstStm.TellEnd() );
+ bDone = true;
+ }
+ }
+ }
+ }
+ else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
+ TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
+ SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
+ {
+ GetData(aSubstFlavor, rDestDoc);
+
+ if( maAny.hasValue() )
+ {
+ Sequence< sal_Int8 > aSeq;
+
+ if( maAny >>= aSeq )
+ {
+ GDIMetaFile aMtf;
+ {
+ SvMemoryStream aSrcStm( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC );
+ SvmReader aReader( aSrcStm );
+ aReader.Read( aMtf );
+ }
+
+ SvMemoryStream aDstStm( 65535, 65535 );
+
+ // taking wmf without file header
+ if ( ConvertGDIMetaFileToWMF( aMtf, aDstStm, nullptr, false ) )
+ {
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
+ aDstStm.TellEnd() );
+ bDone = true;
+ }
+ }
+ }
+ }
+
+ // reset Any if substitute doesn't work
+ if( !bDone && maAny.hasValue() )
+ maAny = Any();
+
+ // if any is not yet filled, use standard format
+ if( !maAny.hasValue() )
+ GetData(rFlavor, rDestDoc);
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ if( !maAny.hasValue() )
+ throw UnsupportedFlavorException();
+ }
+
+ return maAny;
+}
+
+sal_Bool SAL_CALL TransferableHelper::isComplex()
+{
+ // By default everything is complex, until proven otherwise
+ // in the respective document type transferable handler.
+ return true;
+}
+
+Sequence< DataFlavor > SAL_CALL TransferableHelper::getTransferDataFlavors()
+{
+ const SolarMutexGuard aGuard;
+
+ try
+ {
+ if(maFormats.empty())
+ AddSupportedFormats();
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ return comphelper::containerToSequence<DataFlavor>(maFormats);
+}
+
+
+sal_Bool SAL_CALL TransferableHelper::isDataFlavorSupported( const DataFlavor& rFlavor )
+{
+ const SolarMutexGuard aGuard;
+
+ try
+ {
+ if (maFormats.empty())
+ AddSupportedFormats();
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ for (auto const& format : maFormats)
+ {
+ if( TransferableDataHelper::IsEqual( format, rFlavor ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void SAL_CALL TransferableHelper::lostOwnership( const Reference< XClipboard >&, const Reference< XTransferable >& )
+{
+ const SolarMutexGuard aGuard;
+
+ try
+ {
+ if( mxTerminateListener.is() )
+ {
+ Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+ xDesktop->removeTerminateListener( mxTerminateListener );
+
+ mxTerminateListener.clear();
+ }
+
+ ObjectReleased();
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+
+void SAL_CALL TransferableHelper::disposing( const EventObject& )
+{
+}
+
+
+void SAL_CALL TransferableHelper::dragDropEnd( const DragSourceDropEvent& rDSDE )
+{
+ const SolarMutexGuard aGuard;
+
+ try
+ {
+ DragFinished( rDSDE.DropSuccess ? ( rDSDE.DropAction & ~DNDConstants::ACTION_DEFAULT ) : DNDConstants::ACTION_NONE );
+ ObjectReleased();
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+
+void SAL_CALL TransferableHelper::dragEnter( const DragSourceDragEvent& )
+{
+}
+
+
+void SAL_CALL TransferableHelper::dragExit( const DragSourceEvent& )
+{
+}
+
+
+void SAL_CALL TransferableHelper::dragOver( const DragSourceDragEvent& )
+{
+}
+
+
+void SAL_CALL TransferableHelper::dropActionChanged( const DragSourceDragEvent& )
+{
+}
+
+
+sal_Int64 SAL_CALL TransferableHelper::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+
+void TransferableHelper::ImplFlush()
+{
+ if( !mxClipboard.is() )
+ return;
+
+ Reference< XFlushableClipboard > xFlushableClipboard( mxClipboard, UNO_QUERY );
+ SolarMutexReleaser aReleaser;
+
+ try
+ {
+ if( xFlushableClipboard.is() )
+ xFlushableClipboard->flushClipboard();
+ }
+ catch( const css::uno::Exception& )
+ {
+ OSL_FAIL( "Could not flush clipboard" );
+ }
+}
+
+
+void TransferableHelper::AddFormat( SotClipboardFormatId nFormat )
+{
+ DataFlavor aFlavor;
+
+ if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
+ AddFormat( aFlavor );
+}
+
+
+void TransferableHelper::AddFormat( const DataFlavor& rFlavor )
+{
+ bool bAdd = true;
+
+ for (auto & format : maFormats)
+ {
+ if( TransferableDataHelper::IsEqual( format, rFlavor ) )
+ {
+ // update MimeType for SotClipboardFormatId::OBJECTDESCRIPTOR in every case
+ if ((SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId) && mxObjDesc)
+ {
+ DataFlavor aObjDescFlavor;
+
+ SotExchange::GetFormatDataFlavor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDescFlavor );
+ format.MimeType = aObjDescFlavor.MimeType;
+ format.MimeType += ::ImplGetParameterString(*mxObjDesc);
+ }
+
+ bAdd = false;
+ break;
+ }
+ }
+
+ if( !bAdd )
+ return;
+
+ DataFlavorEx aFlavorEx;
+
+ aFlavorEx.MimeType = rFlavor.MimeType;
+ aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
+ aFlavorEx.DataType = rFlavor.DataType;
+ aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
+
+ if ((SotClipboardFormatId::OBJECTDESCRIPTOR == aFlavorEx.mnSotId) && mxObjDesc)
+ aFlavorEx.MimeType += ::ImplGetParameterString(*mxObjDesc);
+
+ maFormats.push_back(aFlavorEx);
+
+ if( SotClipboardFormatId::BITMAP == aFlavorEx.mnSotId )
+ {
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BMP );
+ }
+ else if( SotClipboardFormatId::GDIMETAFILE == aFlavorEx.mnSotId )
+ {
+ AddFormat( SotClipboardFormatId::EMF );
+ AddFormat( SotClipboardFormatId::WMF );
+ }
+}
+
+
+void TransferableHelper::RemoveFormat( SotClipboardFormatId nFormat )
+{
+ DataFlavor aFlavor;
+
+ if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
+ RemoveFormat( aFlavor );
+}
+
+
+void TransferableHelper::RemoveFormat( const DataFlavor& rFlavor )
+{
+ DataFlavorExVector::iterator aIter(maFormats.begin());
+
+ while (aIter != maFormats.end())
+ {
+ if( TransferableDataHelper::IsEqual( *aIter, rFlavor ) )
+ aIter = maFormats.erase(aIter);
+ else
+ ++aIter;
+ }
+}
+
+
+bool TransferableHelper::HasFormat( SotClipboardFormatId nFormat )
+{
+ return std::any_of(maFormats.begin(), maFormats.end(),
+ [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
+}
+
+
+void TransferableHelper::ClearFormats()
+{
+ maFormats.clear();
+ maAny.clear();
+}
+
+
+bool TransferableHelper::SetAny( const Any& rAny )
+{
+ maAny = rAny;
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetString( const OUString& rString )
+{
+ maAny <<= rString;
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetBitmapEx( const BitmapEx& rBitmapEx, const DataFlavor& rFlavor )
+{
+ if( !rBitmapEx.IsEmpty() )
+ {
+ SvMemoryStream aMemStm( 65535, 65535 );
+
+ if(rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
+ {
+ // write a PNG
+ css::uno::Sequence<css::beans::PropertyValue> aFilterData;
+
+#ifdef IOS
+ // Use faster compression on slow devices
+ aFilterData.realloc(aFilterData.getLength() + 1);
+ aFilterData.getArray()[aFilterData.getLength() - 1].Name = "Compression";
+
+ // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed. For a
+ // typical 15 megapixel image from a DSLR, we are talking about a difference of 17 s for
+ // the default compression level vs 4 s for best speed, on an iPad Pro from 2017.
+ //
+ // Sure, the best would be to not have to re-encode the image at all, but have access to
+ // the original JPEG or PNG when there is a such.
+
+ aFilterData.getArray()[aFilterData.getLength() - 1].Value <<= 1;
+#endif
+ vcl::PNGWriter aPNGWriter(rBitmapEx, &aFilterData);
+
+ aPNGWriter.Write(aMemStm);
+ }
+ else
+ {
+ // explicitly use Bitmap::Write with bCompressed = sal_False and bFileHeader = sal_True
+ WriteDIB(rBitmapEx.GetBitmap(), aMemStm, false, true);
+ }
+
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
+ }
+
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetGDIMetaFile( const GDIMetaFile& rMtf )
+{
+ if( rMtf.GetActionSize() )
+ {
+ SvMemoryStream aMemStm( 65535, 65535 );
+
+ SvmWriter aWriter( aMemStm );
+ aWriter.Write( rMtf );
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
+ }
+
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetGraphic( const Graphic& rGraphic )
+{
+ if( rGraphic.GetType() != GraphicType::NONE )
+ {
+ SvMemoryStream aMemStm( 65535, 65535 );
+
+ aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
+ aMemStm.SetCompressMode( SvStreamCompressFlags::NATIVE );
+
+ TypeSerializer aSerializer(aMemStm);
+ aSerializer.writeGraphic(rGraphic);
+
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
+ }
+
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetImageMap( const ImageMap& rIMap )
+{
+ SvMemoryStream aMemStm( 8192, 8192 );
+
+ aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
+ rIMap.Write( aMemStm );
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
+
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetTransferableObjectDescriptor( const TransferableObjectDescriptor& rDesc )
+{
+ PrepareOLE( rDesc );
+
+ SvMemoryStream aMemStm( 1024, 1024 );
+
+ WriteTransferableObjectDescriptor( aMemStm, rDesc );
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
+
+ return maAny.hasValue();
+ }
+
+
+bool TransferableHelper::SetINetBookmark( const INetBookmark& rBmk,
+ const css::datatransfer::DataFlavor& rFlavor )
+{
+ rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
+
+ switch( SotExchange::GetFormat( rFlavor ) )
+ {
+ case SotClipboardFormatId::SOLK:
+ {
+ OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
+ OString sDesc(OUStringToOString(rBmk.GetDescription(), eSysCSet));
+ OStringBuffer sOut;
+ sOut.append(sURL.getLength());
+ sOut.append("@" + sURL);
+ sOut.append(sDesc.getLength());
+ sOut.append("@" + sDesc);
+
+ Sequence< sal_Int8 > aSeq(sOut.getLength());
+ memcpy(aSeq.getArray(), sOut.getStr(), sOut.getLength());
+ maAny <<= aSeq;
+ }
+ break;
+
+ case SotClipboardFormatId::STRING:
+ case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
+ maAny <<= rBmk.GetURL();
+ break;
+
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ {
+ Sequence< sal_Int8 > aSeq( 2048 );
+ char* pSeq = reinterpret_cast< char* >( aSeq.getArray() );
+
+ // strncpy fills the rest with nulls, as we need
+ strncpy( pSeq, OUStringToOString(rBmk.GetURL(), eSysCSet).getStr(), 1024 );
+ strncpy( pSeq + 1024, OUStringToOString(rBmk.GetDescription(), eSysCSet).getStr(), 1024 );
+
+ maAny <<= aSeq;
+ }
+ break;
+
+#ifdef _WIN32
+ case SotClipboardFormatId::FILEGRPDESCRIPTOR:
+ {
+ Sequence< sal_Int8 > aSeq( sizeof( FILEGROUPDESCRIPTORW ) );
+ FILEGROUPDESCRIPTORW* pFDesc = reinterpret_cast<FILEGROUPDESCRIPTORW*>(aSeq.getArray());
+ FILEDESCRIPTORW& rFDesc1 = pFDesc->fgd[ 0 ];
+
+ pFDesc->cItems = 1;
+ memset( &rFDesc1, 0, sizeof( rFDesc1 ) );
+ rFDesc1.dwFlags = FD_LINKUI;
+
+ OUStringBuffer aStr(rBmk.GetDescription());
+ for( size_t nChar = 0; (nChar = std::u16string_view(aStr).find_first_of(u"\\/:*?\"<>|"sv, nChar)) != std::u16string_view::npos; )
+ aStr.remove(nChar, 1);
+
+ aStr.insert(0, "Shortcut to ");
+ aStr.append(".URL");
+ wcscpy( rFDesc1.cFileName, o3tl::toW(aStr.getStr()) );
+
+ maAny <<= aSeq;
+ }
+ break;
+
+ case SotClipboardFormatId::FILECONTENT:
+ {
+ maAny <<= "[InternetShortcut]\x0aURL=" + rBmk.GetURL();
+ }
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetINetImage( const INetImage& rINtImg,
+ const css::datatransfer::DataFlavor& rFlavor )
+{
+ SvMemoryStream aMemStm( 1024, 1024 );
+
+ aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
+ rINtImg.Write( aMemStm, SotExchange::GetFormat( rFlavor ) );
+
+ maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
+
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
+{
+ tools::SvRef<SotTempStream> xStm( new SotTempStream( OUString() ) );
+
+ xStm->SetVersion( SOFFICE_FILEFORMAT_50 );
+
+ if( pUserObject && WriteObject( xStm, pUserObject, nUserObjectId, rFlavor ) )
+ {
+ const sal_uInt32 nLen = xStm->TellEnd();
+ Sequence< sal_Int8 > aSeq( nLen );
+
+ xStm->Seek( STREAM_SEEK_TO_BEGIN );
+ xStm->ReadBytes(aSeq.getArray(), nLen);
+
+ if( nLen && ( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::STRING ) )
+ {
+ //JP 24.7.2001: as I know was this only for the writer application and this
+ // writes now UTF16 format into the stream
+ //JP 6.8.2001: and now it writes UTF8 because then exist no problem with
+ // little / big endians! - Bug 88121
+ maAny <<= OUString( reinterpret_cast< const char* >( aSeq.getConstArray() ), nLen - 1, RTL_TEXTENCODING_UTF8 );
+ }
+ else
+ maAny <<= aSeq;
+ }
+
+ return maAny.hasValue();
+}
+
+
+bool TransferableHelper::WriteObject( tools::SvRef<SotTempStream>&, void*, sal_uInt32, const DataFlavor& )
+{
+ OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
+ return false;
+}
+
+
+void TransferableHelper::DragFinished( sal_Int8 )
+{
+}
+
+
+void TransferableHelper::ObjectReleased()
+{
+}
+
+
+void TransferableHelper::PrepareOLE( const TransferableObjectDescriptor& rObjDesc )
+{
+ mxObjDesc.reset(new TransferableObjectDescriptor(rObjDesc));
+
+ if( HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+}
+
+void TransferableHelper::CopyToClipboard(const Reference<XClipboard>& rClipboard) const
+{
+ if( rClipboard.is() )
+ mxClipboard = rClipboard;
+
+ if( !mxClipboard.is() || mxTerminateListener.is() )
+ return;
+
+ try
+ {
+ TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
+ pThis->mxTerminateListener = new TerminateListener( *pThis );
+ Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+ xDesktop->addTerminateListener( pThis->mxTerminateListener );
+
+ mxClipboard->setContents( pThis, pThis );
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+void TransferableHelper::CopyToClipboard( vcl::Window *pWindow ) const
+{
+ DBG_ASSERT( pWindow, "Window pointer is NULL" );
+ Reference< XClipboard > xClipboard;
+
+ if( pWindow )
+ xClipboard = pWindow->GetClipboard();
+
+ CopyToClipboard(xClipboard);
+}
+
+void TransferableHelper::CopyToSelection(const Reference<XClipboard>& rSelection) const
+{
+ if( !rSelection.is() || mxTerminateListener.is() )
+ return;
+
+ try
+ {
+ TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
+ pThis->mxTerminateListener = new TerminateListener( *pThis );
+ Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
+ xDesktop->addTerminateListener( pThis->mxTerminateListener );
+
+ rSelection->setContents( pThis, pThis );
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+void TransferableHelper::CopyToPrimarySelection() const
+{
+ CopyToSelection(GetSystemPrimarySelection());
+}
+
+void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
+
+{
+ DBG_ASSERT( pWindow, "Window pointer is NULL" );
+ Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
+
+ if( !xDragSource.is() )
+ return;
+
+ /*
+ * #96792# release mouse before actually starting DnD.
+ * This is necessary for the X11 DnD implementation to work.
+ */
+ if( pWindow->IsMouseCaptured() )
+ pWindow->ReleaseMouse();
+
+ const Point aPt( pWindow->GetPointerPosPixel() );
+
+ // On macOS we are forced to execute 'startDrag' synchronously
+ // contrary to the XDragSource interface specification because
+ // we can receive drag events from the system only in the main
+ // thread
+#if !defined(MACOSX)
+ SolarMutexReleaser aReleaser;
+#endif
+
+ try
+ {
+ DragGestureEvent aEvt;
+ aEvt.DragAction = DNDConstants::ACTION_COPY;
+ aEvt.DragOriginX = aPt.X();
+ aEvt.DragOriginY = aPt.Y();
+ aEvt.DragSource = xDragSource;
+
+ xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+void TransferableHelper::ClearPrimarySelection()
+{
+ Reference< XClipboard > xSelection(GetSystemPrimarySelection());
+
+ if( xSelection.is() )
+ xSelection->setContents( nullptr, nullptr );
+}
+
+const Sequence< sal_Int8 >& TransferableHelper::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theTransferableHelperUnoTunnelId;
+ return theTransferableHelperUnoTunnelId.getSeq();
+}
+
+namespace {
+
+class TransferableClipboardNotifier : public ::cppu::WeakImplHelper< XClipboardListener >
+{
+private:
+ ::osl::Mutex& mrMutex;
+ Reference< XClipboardNotifier > mxNotifier;
+ TransferableDataHelper* mpListener;
+
+protected:
+ // XClipboardListener
+ virtual void SAL_CALL changedContents( const clipboard::ClipboardEvent& event ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+
+public:
+ TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex );
+
+ /// determines whether we're currently listening
+ bool isListening() const { return mpListener != nullptr; }
+
+ /// makes the instance non-functional
+ void dispose();
+};
+
+}
+
+TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
+ :mrMutex( _rMutex )
+ ,mxNotifier( _rxClipboard, UNO_QUERY )
+ ,mpListener( &_rListener )
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ if ( mxNotifier.is() )
+ mxNotifier->addClipboardListener( this );
+ else
+ // born dead
+ mpListener = nullptr;
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+
+void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
+{
+ SolarMutexGuard aSolarGuard;
+ // the SolarMutex here is necessary, since
+ // - we cannot call mpListener without our own mutex locked
+ // - Rebind respectively InitFormats (called by Rebind) will
+ // try to lock the SolarMutex, too
+ ::osl::MutexGuard aGuard( mrMutex );
+ if( mpListener )
+ mpListener->Rebind( event.Contents );
+}
+
+
+void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
+{
+ // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
+ dispose();
+}
+
+
+void TransferableClipboardNotifier::dispose()
+{
+ ::osl::MutexGuard aGuard( mrMutex );
+
+ Reference< XClipboardListener > xKeepMeAlive( this );
+
+ if ( mxNotifier.is() )
+ mxNotifier->removeClipboardListener( this );
+ mxNotifier.clear();
+
+ mpListener = nullptr;
+}
+
+struct TransferableDataHelper_Impl
+{
+ ::osl::Mutex maMutex;
+ rtl::Reference<TransferableClipboardNotifier> mxClipboardListener;
+
+ TransferableDataHelper_Impl()
+ {
+ }
+};
+
+TransferableDataHelper::TransferableDataHelper()
+ : mxObjDesc(new TransferableObjectDescriptor)
+ , mxImpl(new TransferableDataHelper_Impl)
+{
+}
+
+TransferableDataHelper::TransferableDataHelper(const Reference< css::datatransfer::XTransferable >& rxTransferable)
+ : mxTransfer(rxTransferable)
+ , mxObjDesc(new TransferableObjectDescriptor)
+ , mxImpl(new TransferableDataHelper_Impl)
+{
+ InitFormats();
+}
+
+TransferableDataHelper::TransferableDataHelper(const TransferableDataHelper& rDataHelper)
+ : mxTransfer(rDataHelper.mxTransfer)
+ , mxClipboard(rDataHelper.mxClipboard)
+ , maFormats(rDataHelper.maFormats)
+ , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
+ , mxImpl(new TransferableDataHelper_Impl)
+{
+}
+
+TransferableDataHelper::TransferableDataHelper(TransferableDataHelper&& rDataHelper) noexcept
+ : mxTransfer(std::move(rDataHelper.mxTransfer))
+ , mxClipboard(std::move(rDataHelper.mxClipboard))
+ , maFormats(std::move(rDataHelper.maFormats))
+ , mxObjDesc(std::move(rDataHelper.mxObjDesc))
+ , mxImpl(new TransferableDataHelper_Impl)
+{
+}
+
+TransferableDataHelper& TransferableDataHelper::operator=( const TransferableDataHelper& rDataHelper )
+{
+ if ( this != &rDataHelper )
+ {
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+
+ const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
+
+ if (bWasClipboardListening)
+ StopClipboardListening();
+
+ mxTransfer = rDataHelper.mxTransfer;
+ maFormats = rDataHelper.maFormats;
+ mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
+ mxClipboard = rDataHelper.mxClipboard;
+
+ if (bWasClipboardListening)
+ StartClipboardListening();
+ }
+
+ return *this;
+}
+
+TransferableDataHelper& TransferableDataHelper::operator=(TransferableDataHelper&& rDataHelper)
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+
+ const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
+
+ if (bWasClipboardListening)
+ StopClipboardListening();
+
+ mxTransfer = std::move(rDataHelper.mxTransfer);
+ maFormats = std::move(rDataHelper.maFormats);
+ mxObjDesc = std::move(rDataHelper.mxObjDesc);
+ mxClipboard = std::move(rDataHelper.mxClipboard);
+
+ if (bWasClipboardListening)
+ StartClipboardListening();
+
+ return *this;
+}
+
+TransferableDataHelper::~TransferableDataHelper()
+{
+ StopClipboardListening( );
+ {
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+ maFormats.clear();
+ mxObjDesc.reset();
+ }
+}
+
+void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
+ DataFlavorExVector& rDataFlavorExVector )
+{
+ try
+ {
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
+ DataFlavorEx aFlavorEx;
+ static const OUStringLiteral aCharsetStr( u"charset" );
+
+
+ for (auto const& rFlavor : rDataFlavorSeq)
+ {
+ Reference< XMimeContentType > xMimeType;
+
+ try
+ {
+ if( !rFlavor.MimeType.isEmpty() )
+ xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ aFlavorEx.MimeType = rFlavor.MimeType;
+ aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
+ aFlavorEx.DataType = rFlavor.DataType;
+ aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
+
+ rDataFlavorExVector.push_back( aFlavorEx );
+
+ // add additional formats for special mime types
+ if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId || SotClipboardFormatId::JPEG == aFlavorEx.mnSotId)
+ {
+ if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
+ {
+ aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
+ rDataFlavorExVector.push_back( aFlavorEx );
+ }
+ }
+ else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
+ {
+ if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
+ {
+ aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
+ rDataFlavorExVector.push_back( aFlavorEx );
+ }
+ }
+ else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
+ {
+ // #104735# HTML_SIMPLE may also be inserted without comments
+ aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
+ rDataFlavorExVector.push_back( aFlavorEx );
+ }
+ else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
+ {
+ // add, if it is a UTF-8 byte buffer
+ if( xMimeType->hasParameter( aCharsetStr ) )
+ {
+ if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
+ xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
+ {
+ rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
+
+ }
+ }
+ }
+ else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
+ {
+ rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
+ }
+ else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
+ {
+ rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
+ }
+ else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
+
+ {
+ rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
+ }
+ else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
+ {
+ rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
+ }
+ else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
+ {
+ rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
+ }
+ }
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+}
+
+void TransferableDataHelper::InitFormats()
+{
+ SolarMutexGuard aSolarGuard;
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+
+ maFormats.clear();
+ mxObjDesc.reset(new TransferableObjectDescriptor);
+
+ if( !mxTransfer.is() )
+ return;
+
+ TransferableDataHelper::FillDataFlavorExVector(mxTransfer->getTransferDataFlavors(), maFormats);
+
+ for (auto const& format : maFormats)
+ {
+ if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
+ {
+ ImplSetParameterString(*mxObjDesc, format);
+ break;
+ }
+ }
+}
+
+
+bool TransferableDataHelper::HasFormat( SotClipboardFormatId nFormat ) const
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+ return std::any_of(maFormats.begin(), maFormats.end(),
+ [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
+}
+
+bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+ for (auto const& format : maFormats)
+ {
+ if( TransferableDataHelper::IsEqual( rFlavor, format ) )
+ return true;
+ }
+
+ return false;
+}
+
+sal_uInt32 TransferableDataHelper::GetFormatCount() const
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+ return maFormats.size();
+}
+
+SotClipboardFormatId TransferableDataHelper::GetFormat( sal_uInt32 nFormat ) const
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+ DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
+ return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
+}
+
+DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+ DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
+
+ DataFlavor aRet;
+
+ if (nFormat < maFormats.size())
+ aRet = maFormats[nFormat];
+
+ return aRet;
+}
+
+
+Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
+{
+ Reference< XTransferable > xRet;
+
+ if( mxTransfer.is() )
+ {
+ try
+ {
+ xRet = mxTransfer;
+
+ // do a dummy call to check, if this interface is valid (nasty)
+ xRet->getTransferDataFlavors();
+
+ }
+ catch( const css::uno::Exception& )
+ {
+ xRet.clear();
+ }
+ }
+
+ return xRet;
+}
+
+
+Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
+{
+ Any aReturn;
+
+ DataFlavor aFlavor;
+ if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
+ aReturn = GetAny(aFlavor, rDestDoc);
+
+ return aReturn;
+}
+
+Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+ Any aRet;
+
+ try
+ {
+ if( mxTransfer.is() )
+ {
+ const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
+
+ Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
+
+ if( nRequestFormat != SotClipboardFormatId::NONE )
+ {
+ // try to get alien format first
+ for (auto const& format : maFormats)
+ {
+ if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
+ {
+// tdf#133365: only release solar mutex on Windows
+#ifdef _WIN32
+ // tdf#133527: first, make sure that we actually hold the mutex
+ SolarMutexGuard g;
+ // Our own thread may handle the nested IDataObject::GetData call,
+ // and try to acquire solar mutex
+ SolarMutexReleaser r;
+#endif // _WIN32
+
+ if (xTransfer2.is())
+ aRet = xTransfer2->getTransferData2(format, rDestDoc);
+ else
+ aRet = mxTransfer->getTransferData(format);
+ }
+
+ if( aRet.hasValue() )
+ break;
+ }
+ }
+
+ if( !aRet.hasValue() )
+ {
+// tdf#133365: only release solar mutex on Windows
+#ifdef _WIN32
+ // tdf#133527: first, make sure that we actually hold the mutex
+ SolarMutexGuard g;
+ // Our own thread may handle the nested IDataObject::GetData call,
+ // and try to acquire solar mutex
+ SolarMutexReleaser r;
+#endif // _WIN32
+
+ if (xTransfer2.is())
+ aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
+ else
+ aRet = mxTransfer->getTransferData(rFlavor);
+ }
+ }
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+
+ return aRet;
+}
+
+
+bool TransferableDataHelper::GetString( SotClipboardFormatId nFormat, OUString& rStr ) const
+{
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
+}
+
+
+bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr ) const
+{
+ Any aAny = GetAny(rFlavor, OUString());
+ bool bRet = false;
+
+ if( aAny.hasValue() )
+ {
+ OUString aOUString;
+ Sequence< sal_Int8 > aSeq;
+
+ if( aAny >>= aOUString )
+ {
+ rStr = aOUString;
+ bRet = true;
+ }
+ else if( aAny >>= aSeq )
+ {
+
+ const char* pChars = reinterpret_cast< const char* >( aSeq.getConstArray() );
+ sal_Int32 nLen = aSeq.getLength();
+
+ //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
+ //DVO 2002-05-27: strip _all_ trailing zeros
+ while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
+ --nLen;
+
+ rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+
+bool TransferableDataHelper::GetBitmapEx( SotClipboardFormatId nFormat, BitmapEx& rBmpEx ) const
+{
+ if(SotClipboardFormatId::BITMAP == nFormat)
+ {
+ // try to get PNG first
+ DataFlavor aFlavor;
+
+ if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
+ {
+ if(GetBitmapEx(aFlavor, rBmpEx))
+ {
+ return true;
+ }
+ }
+
+ // then JPEG
+ if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor))
+ {
+ if(GetBitmapEx(aFlavor, rBmpEx))
+ {
+ return true;
+ }
+ }
+ }
+
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
+}
+
+
+bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx ) const
+{
+ tools::SvRef<SotTempStream> xStm;
+ DataFlavor aSubstFlavor;
+ bool bRet(GetSotStorageStream(rFlavor, xStm));
+ bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
+ bool bSuppressJPEG(false);
+
+ if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
+ {
+ // when no direct success, try if PNG is available
+ bRet = GetSotStorageStream(aSubstFlavor, xStm);
+ bSuppressJPEG = bRet;
+ }
+
+ if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
+ {
+ bRet = GetSotStorageStream(aSubstFlavor, xStm);
+ bSuppressPNG = bRet;
+ }
+
+ if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
+ {
+ // when no direct success, try if BMP is available
+ bRet = GetSotStorageStream(aSubstFlavor, xStm);
+ bSuppressPNG = bRet;
+ bSuppressJPEG = bRet;
+ }
+
+ if(bRet)
+ {
+ if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
+ {
+ // it's a PNG, import to BitmapEx
+ vcl::PngImageReader aPNGReader(*xStm);
+ rBmpEx = aPNGReader.read();
+ }
+ else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
+ {
+ // it's a JPEG, import to BitmapEx
+ GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+ Graphic aGraphic;
+ if (rFilter.ImportGraphic(aGraphic, u"", *xStm) == ERRCODE_NONE)
+ rBmpEx = aGraphic.GetBitmapEx();
+ }
+
+ if(rBmpEx.IsEmpty())
+ {
+ Bitmap aBitmap;
+ AlphaMask aMask;
+
+ // explicitly use Bitmap::Read with bFileHeader = sal_True
+ // #i124085# keep DIBV5 for read from clipboard, but should not happen
+ ReadDIBV5(aBitmap, aMask, *xStm);
+
+ if(aMask.GetBitmap().IsEmpty())
+ {
+ rBmpEx = aBitmap;
+ }
+ else
+ {
+ rBmpEx = BitmapEx(aBitmap, aMask);
+ }
+ }
+
+ bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
+
+ /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
+ problem is, that some graphics are inserted much too big because the nXPelsPerMeter
+ and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
+ Due to this reason the following code assumes that bitmaps with a logical size
+ greater than 50 cm aren't having the correct mapmode set.
+
+ The following code should be removed if DDBs and DIBs are supported via clipboard
+ properly.
+ */
+ if(bRet)
+ {
+ const MapMode aMapMode(rBmpEx.GetPrefMapMode());
+
+ if(MapUnit::MapPixel != aMapMode.GetMapUnit())
+ {
+ const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
+
+ // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
+ // the described 50 cm (which is 50000 100th mm)
+ if((aSize.Width() > 50000) || (aSize.Height() > 50000))
+ {
+ rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
+
+ // #i122388# also adapt size by applying the mew MapMode
+ const Size aNewSize(o3tl::convert(aSize, o3tl::Length::mm100, o3tl::Length::pt));
+ rBmpEx.SetPrefSize(aNewSize);
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+
+bool TransferableDataHelper::GetGDIMetaFile(SotClipboardFormatId nFormat, GDIMetaFile& rMtf, size_t nMaxActions) const
+{
+ DataFlavor aFlavor;
+ return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
+ GetGDIMetaFile(aFlavor, rMtf) &&
+ (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
+}
+
+
+bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf ) const
+{
+ tools::SvRef<SotTempStream> xStm;
+ DataFlavor aSubstFlavor;
+ bool bRet = false;
+
+ if( GetSotStorageStream( rFlavor, xStm ) )
+ {
+ SvmReader aReader( *xStm );
+ aReader.Read( rMtf );
+ bRet = ( xStm->GetError() == ERRCODE_NONE );
+ }
+
+ if( !bRet &&
+ HasFormat( SotClipboardFormatId::EMF ) &&
+ SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
+ GetSotStorageStream( aSubstFlavor, xStm ) )
+ {
+ Graphic aGraphic;
+
+ if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
+ {
+ rMtf = aGraphic.GetGDIMetaFile();
+ bRet = true;
+ }
+ }
+
+ if( !bRet &&
+ HasFormat( SotClipboardFormatId::WMF ) &&
+ SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
+ GetSotStorageStream( aSubstFlavor, xStm ) )
+ {
+ Graphic aGraphic;
+
+ if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
+ {
+ rMtf = aGraphic.GetGDIMetaFile();
+ bRet = true;
+ }
+ }
+
+ return bRet;
+}
+
+
+bool TransferableDataHelper::GetGraphic( SotClipboardFormatId nFormat, Graphic& rGraphic ) const
+{
+ if(SotClipboardFormatId::BITMAP == nFormat)
+ {
+ // try to get PNG first
+ DataFlavor aFlavor;
+
+ if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
+ {
+ if(GetGraphic(aFlavor, rGraphic))
+ {
+ return true;
+ }
+ }
+ }
+
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
+}
+
+
+bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic ) const
+{
+ DataFlavor aFlavor;
+ bool bRet = false;
+
+ if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
+ TransferableDataHelper::IsEqual(aFlavor, rFlavor))
+ {
+ // try to get PNG first
+ BitmapEx aBmpEx;
+
+ bRet = GetBitmapEx( aFlavor, aBmpEx );
+ if( bRet )
+ rGraphic = aBmpEx;
+ }
+ else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
+ TransferableDataHelper::IsEqual(aFlavor, rFlavor))
+ {
+ Graphic aGraphic;
+ tools::SvRef<SotTempStream> xStm;
+ if (GetSotStorageStream(rFlavor, xStm))
+ {
+ if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
+ {
+ rGraphic = aGraphic;
+ bRet = true;
+ }
+ }
+ }
+ else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
+ {
+ BitmapEx aBitmapEx;
+
+ bRet = GetBitmapEx(aFlavor, aBitmapEx);
+ if (bRet)
+ rGraphic = aBitmapEx;
+ }
+ else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
+ TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
+ {
+ BitmapEx aBmpEx;
+
+ bRet = GetBitmapEx( aFlavor, aBmpEx );
+ if( bRet )
+ rGraphic = aBmpEx;
+ }
+ else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
+ TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
+ {
+ GDIMetaFile aMtf;
+
+ bRet = GetGDIMetaFile( aFlavor, aMtf );
+ if( bRet )
+ rGraphic = aMtf;
+ }
+ else
+ {
+ tools::SvRef<SotTempStream> xStm;
+
+ if( GetSotStorageStream( rFlavor, xStm ) )
+ {
+ TypeSerializer aSerializer(*xStm);
+ aSerializer.readGraphic(rGraphic);
+ bRet = ( xStm->GetError() == ERRCODE_NONE );
+ }
+ }
+
+ return bRet;
+}
+
+
+bool TransferableDataHelper::GetImageMap( SotClipboardFormatId nFormat, ImageMap& rIMap ) const
+{
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
+}
+
+
+bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap ) const
+{
+ tools::SvRef<SotTempStream> xStm;
+ bool bRet = GetSotStorageStream( rFlavor, xStm );
+
+ if( bRet )
+ {
+ rIMap.Read( *xStm );
+ bRet = ( xStm->GetError() == ERRCODE_NONE );
+ }
+
+ return bRet;
+}
+
+
+bool TransferableDataHelper::GetTransferableObjectDescriptor( SotClipboardFormatId nFormat, TransferableObjectDescriptor& rDesc )
+{
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
+}
+
+
+bool TransferableDataHelper::GetTransferableObjectDescriptor( TransferableObjectDescriptor& rDesc )
+{
+ rDesc = *mxObjDesc;
+ return true;
+}
+
+
+bool TransferableDataHelper::GetINetBookmark( SotClipboardFormatId nFormat, INetBookmark& rBmk ) const
+{
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
+}
+
+
+bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk ) const
+{
+ if( !HasFormat( rFlavor ))
+ return false;
+
+ bool bRet = false;
+ const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ switch( nFormat )
+ {
+ case SotClipboardFormatId::SOLK:
+ case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
+ {
+ OUString aString;
+ if( GetString( rFlavor, aString ) )
+ {
+ if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
+ {
+ rBmk = INetBookmark( aString, aString );
+ bRet = true;
+ }
+ else
+ {
+ OUString aURL, aDesc;
+ sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
+
+ if( !nLen && aString[ 0 ] != '0' )
+ {
+ SAL_INFO( "svtools", "SOLK: 1. len=0" );
+ }
+ if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
+ {
+ SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
+ }
+ aURL = aString.copy( nStart + 1, nLen );
+
+ aString = aString.replaceAt( 0, nStart + 1 + nLen, u"" );
+ nStart = aString.indexOf( '@' );
+ nLen = aString.toInt32();
+
+ if( !nLen && aString[ 0 ] != '0' )
+ {
+ SAL_INFO( "svtools", "SOLK: 2. len=0" );
+ }
+ if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
+ {
+ SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
+ }
+ aDesc = aString.copy( nStart+1, nLen );
+
+ rBmk = INetBookmark( aURL, aDesc );
+ bRet = true;
+ }
+ }
+ }
+ break;
+
+ case SotClipboardFormatId::NETSCAPE_BOOKMARK:
+ {
+ Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
+
+ if (2048 == aSeq.getLength())
+ {
+ const char* p1 = reinterpret_cast< const char* >( aSeq.getConstArray() );
+ const char* p2 = reinterpret_cast< const char* >( aSeq.getConstArray() ) + 1024;
+ rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
+ OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
+ bRet = true;
+ }
+ }
+ break;
+
+#ifdef _WIN32
+ case SotClipboardFormatId::FILEGRPDESCRIPTOR:
+ {
+ Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
+
+ if (aSeq.getLength())
+ {
+ FILEGROUPDESCRIPTORW const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTORW const *>(aSeq.getConstArray());
+
+ if( pFDesc->cItems )
+ {
+ OUString aDesc( o3tl::toU(pFDesc->fgd[ 0 ].cFileName) );
+
+ if( ( aDesc.getLength() > 4 ) && aDesc.endsWithIgnoreAsciiCase(".URL") )
+ {
+ std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( aDesc ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ StreamMode::STD_READ ));
+
+ if( !pStream || pStream->GetError() )
+ {
+ DataFlavor aFileContentFlavor;
+
+ aSeq.realloc( 0 );
+ pStream.reset();
+
+ if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
+ {
+ aSeq = GetSequence(aFileContentFlavor, OUString());
+ if (aSeq.getLength())
+ pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
+ }
+ }
+
+ if( pStream )
+ {
+ OString aLine;
+ bool bInA = false, bInW = false, bAFound = false;
+
+ while( pStream->ReadLine( aLine ) )
+ {
+ if (aLine.startsWithIgnoreAsciiCase("[InternetShortcut", &aLine))
+ {
+ // May be [InternetShortcut], or [InternetShortcut.A], or
+ // [InternetShortcut.W] (the latter has UTF-7-encoded URL)
+ bInW = aLine.equalsIgnoreAsciiCase(".W]");
+ bInA = !bAFound && !bInW
+ && (aLine == "]" || aLine.equalsIgnoreAsciiCase(".A]"));
+ }
+ else if (aLine.startsWith("["))
+ {
+ bInA = bInW = false;
+ }
+ else if ((bInA || bInW) && aLine.startsWithIgnoreAsciiCase("URL="))
+ {
+ auto eTextEncoding = bInW ? RTL_TEXTENCODING_UTF7
+ : osl_getThreadTextEncoding();
+ rBmk = INetBookmark( OStringToOUString(aLine.subView(4), eTextEncoding),
+ aDesc.copy(0, aDesc.getLength() - 4) );
+ bRet = true;
+ if (bInW)
+ break;
+ else
+ bAFound = true; // Keep looking for "W"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+#endif
+ default: break;
+ }
+ return bRet;
+}
+
+
+bool TransferableDataHelper::GetINetImage( SotClipboardFormatId nFormat,
+ INetImage& rINtImg ) const
+{
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
+}
+
+
+bool TransferableDataHelper::GetINetImage(
+ const css::datatransfer::DataFlavor& rFlavor,
+ INetImage& rINtImg ) const
+{
+ tools::SvRef<SotTempStream> xStm;
+ bool bRet = GetSotStorageStream( rFlavor, xStm );
+
+ if( bRet )
+ bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
+ return bRet;
+}
+
+
+bool TransferableDataHelper::GetFileList( SotClipboardFormatId nFormat,
+ FileList& rFileList ) const
+{
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
+}
+
+
+bool TransferableDataHelper::GetFileList( FileList& rFileList ) const
+{
+ tools::SvRef<SotTempStream> xStm;
+ bool bRet = false;
+
+ for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
+ {
+ if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
+ {
+ const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
+
+ if( GetSotStorageStream( aFlavor, xStm ) )
+ {
+ if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
+ {
+ OStringBuffer aDiskString;
+
+ while( xStm->ReadLine( aDiskString ) )
+ if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
+ rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
+
+ bRet = true;
+ }
+ else
+ bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
+ }
+ }
+ }
+
+ return bRet;
+}
+
+
+Sequence<sal_Int8> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
+{
+ DataFlavor aFlavor;
+ if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
+ return Sequence<sal_Int8>();
+
+ return GetSequence(aFlavor, rDestDoc);
+}
+
+Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
+{
+ const Any aAny = GetAny(rFlavor, rDestDoc);
+ Sequence<sal_Int8> aSeq;
+ if (aAny.hasValue())
+ aAny >>= aSeq;
+
+ return aSeq;
+}
+
+
+bool TransferableDataHelper::GetSotStorageStream( SotClipboardFormatId nFormat, tools::SvRef<SotTempStream>& rxStream ) const
+{
+ DataFlavor aFlavor;
+ return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
+}
+
+
+bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotTempStream>& rxStream ) const
+{
+ Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
+
+ if (aSeq.hasElements())
+ {
+ rxStream = new SotTempStream( "" );
+ rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
+ rxStream->Seek( 0 );
+ }
+
+ return aSeq.hasElements();
+}
+
+Reference<XInputStream> TransferableDataHelper::GetInputStream( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
+{
+ DataFlavor aFlavor;
+ if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
+ return Reference<XInputStream>();
+
+ return GetInputStream(aFlavor, rDestDoc);
+}
+
+Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
+{
+ Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
+
+ if (!aSeq.hasElements())
+ return Reference<XInputStream>();
+
+ Reference<XInputStream> xStream(new comphelper::SequenceInputStream(aSeq));
+ return xStream;
+}
+
+void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
+{
+ mxTransfer = _rxNewContent;
+ InitFormats();
+}
+
+bool TransferableDataHelper::StartClipboardListening( )
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+
+ StopClipboardListening( );
+
+ mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
+
+ return mxImpl->mxClipboardListener->isListening();
+}
+
+void TransferableDataHelper::StopClipboardListening( )
+{
+ ::osl::MutexGuard aGuard(mxImpl->maMutex);
+
+ if (mxImpl->mxClipboardListener.is())
+ {
+ mxImpl->mxClipboardListener->dispose();
+ mxImpl->mxClipboardListener.clear();
+ }
+}
+
+TransferableDataHelper TransferableDataHelper::CreateFromClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& rClipboard)
+{
+ TransferableDataHelper aRet;
+
+ if( rClipboard.is() )
+ {
+ try
+ {
+ Reference< XTransferable > xTransferable( rClipboard->getContents() );
+
+ if( xTransferable.is() )
+ {
+ aRet = TransferableDataHelper( xTransferable );
+ // also copy the clipboard
+ aRet.mxClipboard = rClipboard;
+ }
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+ }
+
+ return aRet;
+}
+
+TransferableDataHelper TransferableDataHelper::CreateFromSystemClipboard( vcl::Window * pWindow )
+{
+ DBG_ASSERT( pWindow, "Window pointer is NULL" );
+
+ Reference< XClipboard > xClipboard;
+
+ if( pWindow )
+ xClipboard = pWindow->GetClipboard();
+
+ return CreateFromClipboard(xClipboard);
+}
+
+TransferableDataHelper TransferableDataHelper::CreateFromPrimarySelection()
+{
+ Reference< XClipboard > xSelection(GetSystemPrimarySelection());
+ TransferableDataHelper aRet;
+
+ if( xSelection.is() )
+ {
+ SolarMutexReleaser aReleaser;
+
+ try
+ {
+ Reference< XTransferable > xTransferable( xSelection->getContents() );
+
+ if( xTransferable.is() )
+ {
+ aRet = TransferableDataHelper( xTransferable );
+ aRet.mxClipboard = xSelection;
+ }
+ }
+ catch( const css::uno::Exception& )
+ {
+ }
+ }
+
+ return aRet;
+}
+
+bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
+ const css::datatransfer::DataFlavor& rRequestFlavor )
+{
+ Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ bool bRet = false;
+
+ try
+ {
+ Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
+
+ Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
+ Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
+
+ if( xRequestType1.is() && xRequestType2.is() )
+ {
+ if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
+ {
+ if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
+ {
+ // special handling for text/plain media types
+ static const OUStringLiteral aCharsetString( u"charset" );
+
+ if( !xRequestType2->hasParameter( aCharsetString ) ||
+ xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
+ xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
+ {
+ bRet = true;
+ }
+ }
+ else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
+ {
+ // special handling for application/x-openoffice media types
+ static const OUStringLiteral aFormatString( u"windows_formatname" );
+
+ if( xRequestType1->hasParameter( aFormatString ) &&
+ xRequestType2->hasParameter( aFormatString ) &&
+ xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
+ {
+ bRet = true;
+ }
+ }
+ else
+ bRet = true;
+ }
+ }
+ }
+ catch( const css::uno::Exception& )
+ {
+ bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */