LibreOffice Module vcl (master)  1
transfer.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #ifdef _WIN32
21 #include <prewin.h>
22 #include <postwin.h>
23 #include <shlobj.h>
24 #endif
25 #include <osl/mutex.hxx>
26 #include <rtl/uri.hxx>
27 #include <sal/log.hxx>
28 #include <tools/debug.hxx>
29 #include <tools/urlobj.hxx>
31 #include <sot/exchange.hxx>
32 #include <sot/storage.hxx>
33 #include <vcl/bitmap.hxx>
34 #include <vcl/gdimtf.hxx>
35 #include <vcl/graph.hxx>
36 #include <vcl/cvtgrf.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/window.hxx>
39 #include <comphelper/fileformat.h>
42 #include <comphelper/sequence.hxx>
43 #include <sot/filelist.hxx>
44 #include <cppuhelper/implbase.hxx>
45 
46 #include <comphelper/seqstream.hxx>
47 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
48 #include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
49 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
50 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
51 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
52 #include <com/sun/star/datatransfer/XTransferable2.hpp>
53 #include <com/sun/star/frame/Desktop.hpp>
54 
55 #include <svl/urlbmk.hxx>
56 #include <vcl/inetimg.hxx>
57 #include <vcl/wmf.hxx>
58 #include <vcl/imap.hxx>
59 #include <vcl/transfer.hxx>
60 #include <rtl/strbuf.hxx>
61 #include <cstdio>
62 #include <vcl/dibtools.hxx>
63 #include <vcl/pngread.hxx>
64 #include <vcl/pngwrite.hxx>
65 #include <vcl/graphicfilter.hxx>
66 #include <memory>
67 #include <utility>
68 #include <vcl/TypeSerializer.hxx>
69 
70 using namespace ::com::sun::star::uno;
71 using namespace ::com::sun::star::lang;
72 using namespace ::com::sun::star::frame;
73 using namespace ::com::sun::star::io;
74 using namespace ::com::sun::star::datatransfer;
76 using namespace ::com::sun::star::datatransfer::dnd;
77 
78 
79 #define TOD_SIG1 0x01234567
80 #define TOD_SIG2 0x89abcdef
81 
83 {
84  const sal_uInt32 nFirstPos = rOStm.Tell(), nViewAspect = rObjDesc.mnViewAspect;
85  const sal_uInt32 nSig1 = TOD_SIG1, nSig2 = TOD_SIG2;
86 
87  rOStm.SeekRel( 4 );
88  WriteSvGlobalName( rOStm, rObjDesc.maClassName );
89  rOStm.WriteUInt32( nViewAspect );
90  rOStm.WriteInt32( rObjDesc.maSize.Width() );
91  rOStm.WriteInt32( rObjDesc.maSize.Height() );
92  rOStm.WriteInt32( rObjDesc.maDragStartPos.X() );
93  rOStm.WriteInt32( rObjDesc.maDragStartPos.Y() );
94  rOStm.WriteUniOrByteString( rObjDesc.maTypeName, osl_getThreadTextEncoding() );
95  rOStm.WriteUniOrByteString( rObjDesc.maDisplayName, osl_getThreadTextEncoding() );
96  rOStm.WriteUInt32( nSig1 ).WriteUInt32( nSig2 );
97 
98  const sal_uInt32 nLastPos = rOStm.Tell();
99 
100  rOStm.Seek( nFirstPos );
101  rOStm.WriteUInt32( nLastPos - nFirstPos );
102  rOStm.Seek( nLastPos );
103 
104  return rOStm;
105 }
106 
107 
108 // the reading of the parameter is done using the special service css::datatransfer::MimeContentType,
109 // a similar approach should be implemented for creation of the mimetype string;
110 // for now the set of acceptable characters has to be hardcoded, in future it should be part of the service that creates the mimetype
111 
112 static OUString ImplGetParameterString( const TransferableObjectDescriptor& rObjDesc )
113 {
114  const OUString aClassName( rObjDesc.maClassName.GetHexName() );
115  OUString aParams;
116 
117  if( !aClassName.isEmpty() )
118  {
119  aParams += ";classname=\"" + aClassName + "\"";
120  }
121 
122  if( !rObjDesc.maTypeName.isEmpty() )
123  {
124  aParams += ";typename=\"" + rObjDesc.maTypeName + "\"";
125  }
126 
127  if( !rObjDesc.maDisplayName.isEmpty() )
128  {
129  // the display name might contain unacceptable characters, encode all of them
130  // this seems to be the only parameter currently that might contain such characters
131  sal_Bool pToAccept[128];
132  for (sal_Bool & rb : pToAccept)
133  rb = false;
134 
135  const char aQuotedParamChars[] =
136  "()<>@,;:/[]?=!#$&'*+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~. ";
137 
138  for ( sal_Int32 nInd = 0; nInd < RTL_CONSTASCII_LENGTH(aQuotedParamChars); ++nInd )
139  {
140  sal_Unicode nChar = aQuotedParamChars[nInd];
141  if ( nChar < 128 )
142  pToAccept[nChar] = true;
143  }
144 
145  aParams += ";displayname=\""
146  + rtl::Uri::encode(
147  rObjDesc.maDisplayName, pToAccept, rtl_UriEncodeIgnoreEscapes,
148  RTL_TEXTENCODING_UTF8)
149  + "\"";
150  }
151 
152  aParams += ";viewaspect=\"" + OUString::number(rObjDesc.mnViewAspect)
153  + "\";width=\"" + OUString::number(rObjDesc.maSize.Width())
154  + "\";height=\"" + OUString::number(rObjDesc.maSize.Height())
155  + "\";posx=\"" + OUString::number(rObjDesc.maDragStartPos.X())
156  + "\";posy=\"" + OUString::number(rObjDesc.maDragStartPos.X()) + "\"";
157 
158  return aParams;
159 }
160 
161 
162 static void ImplSetParameterString( TransferableObjectDescriptor& rObjDesc, const DataFlavorEx& rFlavorEx )
163 {
165 
166  try
167  {
168  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
169 
170  Reference< XMimeContentType > xMimeType( xMimeFact->createMimeContentType( rFlavorEx.MimeType ) );
171 
172  if( xMimeType.is() )
173  {
174  const OUString aClassNameString( "classname" );
175  const OUString aTypeNameString( "typename" );
176  const OUString aDisplayNameString( "displayname" );
177  const OUString aViewAspectString( "viewaspect" );
178  const OUString aWidthString( "width" );
179  const OUString aHeightString( "height" );
180  const OUString aPosXString( "posx" );
181  const OUString aPosYString( "posy" );
182 
183  if( xMimeType->hasParameter( aClassNameString ) )
184  {
185  rObjDesc.maClassName.MakeId( xMimeType->getParameterValue( aClassNameString ) );
186  }
187 
188  if( xMimeType->hasParameter( aTypeNameString ) )
189  {
190  rObjDesc.maTypeName = xMimeType->getParameterValue( aTypeNameString );
191  }
192 
193  if( xMimeType->hasParameter( aDisplayNameString ) )
194  {
195  // the display name might contain unacceptable characters, in this case they should be encoded
196  // this seems to be the only parameter currently that might contain such characters
197  rObjDesc.maDisplayName = ::rtl::Uri::decode( xMimeType->getParameterValue( aDisplayNameString ), rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
198  }
199 
200  if( xMimeType->hasParameter( aViewAspectString ) )
201  {
202  rObjDesc.mnViewAspect = static_cast< sal_uInt16 >( xMimeType->getParameterValue( aViewAspectString ).toInt32() );
203  }
204 
205  if( xMimeType->hasParameter( aWidthString ) )
206  {
207  rObjDesc.maSize.setWidth( xMimeType->getParameterValue( aWidthString ).toInt32() );
208  }
209 
210  if( xMimeType->hasParameter( aHeightString ) )
211  {
212  rObjDesc.maSize.setHeight( xMimeType->getParameterValue( aHeightString ).toInt32() );
213  }
214 
215  if( xMimeType->hasParameter( aPosXString ) )
216  {
217  rObjDesc.maDragStartPos.setX( xMimeType->getParameterValue( aPosXString ).toInt32() );
218  }
219 
220  if( xMimeType->hasParameter( aPosYString ) )
221  {
222  rObjDesc.maDragStartPos.setY( xMimeType->getParameterValue( aPosYString ).toInt32() );
223  }
224  }
225  }
226  catch( const css::uno::Exception& )
227  {
228  }
229 }
230 
231 
233  mrParent( rTransferableHelper )
234 {
235 }
236 
237 
239 {
240 }
241 
242 
243 void SAL_CALL TransferableHelper::TerminateListener::disposing( const EventObject& )
244 {
245 }
246 
247 
249 {
250 }
251 
252 
254 {
255  mrParent.ImplFlush();
256 }
257 
259 {
260  return "com.sun.star.comp.svt.TransferableHelperTerminateListener";
261 }
262 
263 sal_Bool SAL_CALL TransferableHelper::TerminateListener::supportsService(const OUString& /*rServiceName*/)
264 {
265  return false;
266 }
267 
269 {
270  return {};
271 }
272 
274 {
275  css::uno::Reference<css::frame::XTerminateListener> listener;
276  {
277  const SolarMutexGuard aGuard;
278  std::swap(listener, mxTerminateListener);
279  }
280  if (listener.is()) {
281  Desktop::create(comphelper::getProcessComponentContext())->removeTerminateListener(
282  listener);
283  }
284 }
285 
286 Any SAL_CALL TransferableHelper::getTransferData( const DataFlavor& rFlavor )
287 {
288  return getTransferData2(rFlavor, OUString());
289 }
290 
291 Any SAL_CALL TransferableHelper::getTransferData2( const DataFlavor& rFlavor, const OUString& rDestDoc )
292 {
293  if( !maAny.hasValue() || maFormats.empty() || ( maLastFormat != rFlavor.MimeType ) )
294  {
295  const SolarMutexGuard aGuard;
296 
297  maLastFormat = rFlavor.MimeType;
298  maAny = Any();
299 
300  try
301  {
302  DataFlavor aSubstFlavor;
303  bool bDone = false;
304 
305  // add formats if not already done
306  if (maFormats.empty())
308 
309  // check alien formats first and try to get a substitution format
310  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aSubstFlavor ) &&
311  TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) )
312  {
313  GetData(aSubstFlavor, rDestDoc);
314  bDone = maAny.hasValue();
315  }
316  else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor )
317  && TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor )
318  && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BITMAP, aSubstFlavor))
319  {
320  GetData(aSubstFlavor, rDestDoc);
321  bDone = true;
322  }
323  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
324  TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
325  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
326  {
327  GetData(aSubstFlavor, rDestDoc);
328 
329  if( maAny.hasValue() )
330  {
332 
333  if( maAny >>= aSeq )
334  {
335  std::unique_ptr<SvMemoryStream> pSrcStm(new SvMemoryStream( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC ));
336  GDIMetaFile aMtf;
337 
338  ReadGDIMetaFile( *pSrcStm, aMtf );
339  pSrcStm.reset();
340 
341  Graphic aGraphic( aMtf );
342  SvMemoryStream aDstStm( 65535, 65535 );
343 
344  if( GraphicConverter::Export( aDstStm, aGraphic, ConvertDataFormat::EMF ) == ERRCODE_NONE )
345  {
346  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
347  aDstStm.TellEnd() );
348  bDone = true;
349  }
350  }
351  }
352  }
353  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
354  TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
355  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
356  {
357  GetData(aSubstFlavor, rDestDoc);
358 
359  if( maAny.hasValue() )
360  {
362 
363  if( maAny >>= aSeq )
364  {
365  std::unique_ptr<SvMemoryStream> pSrcStm(new SvMemoryStream( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC ));
366  GDIMetaFile aMtf;
367 
368  ReadGDIMetaFile( *pSrcStm, aMtf );
369  pSrcStm.reset();
370 
371  SvMemoryStream aDstStm( 65535, 65535 );
372 
373  // taking wmf without file header
374  if ( ConvertGDIMetaFileToWMF( aMtf, aDstStm, nullptr, false ) )
375  {
376  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
377  aDstStm.TellEnd() );
378  bDone = true;
379  }
380  }
381  }
382  }
383 
384  // reset Any if substitute doesn't work
385  if( !bDone && maAny.hasValue() )
386  maAny = Any();
387 
388  // if any is not yet filled, use standard format
389  if( !maAny.hasValue() )
390  GetData(rFlavor, rDestDoc);
391  }
392  catch( const css::uno::Exception& )
393  {
394  }
395 
396  if( !maAny.hasValue() )
397  throw UnsupportedFlavorException();
398  }
399 
400  return maAny;
401 }
402 
404 {
405  // By default everything is complex, until proven otherwise
406  // in the respective document type transferable handler.
407  return true;
408 }
409 
410 Sequence< DataFlavor > SAL_CALL TransferableHelper::getTransferDataFlavors()
411 {
412  const SolarMutexGuard aGuard;
413 
414  try
415  {
416  if(maFormats.empty())
418  }
419  catch( const css::uno::Exception& )
420  {
421  }
422 
423  return comphelper::containerToSequence<DataFlavor>(maFormats);
424 }
425 
426 
427 sal_Bool SAL_CALL TransferableHelper::isDataFlavorSupported( const DataFlavor& rFlavor )
428 {
429  const SolarMutexGuard aGuard;
430 
431  try
432  {
433  if (maFormats.empty())
435  }
436  catch( const css::uno::Exception& )
437  {
438  }
439 
440  for (auto const& format : maFormats)
441  {
442  if( TransferableDataHelper::IsEqual( format, rFlavor ) )
443  {
444  return true;
445  }
446  }
447 
448  return false;
449 }
450 
451 
452 void SAL_CALL TransferableHelper::lostOwnership( const Reference< XClipboard >&, const Reference< XTransferable >& )
453 {
454  const SolarMutexGuard aGuard;
455 
456  try
457  {
458  if( mxTerminateListener.is() )
459  {
460  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
461  xDesktop->removeTerminateListener( mxTerminateListener );
462 
463  mxTerminateListener.clear();
464  }
465 
466  ObjectReleased();
467  }
468  catch( const css::uno::Exception& )
469  {
470  }
471 }
472 
473 
474 void SAL_CALL TransferableHelper::disposing( const EventObject& )
475 {
476 }
477 
478 
479 void SAL_CALL TransferableHelper::dragDropEnd( const DragSourceDropEvent& rDSDE )
480 {
481  const SolarMutexGuard aGuard;
482 
483  try
484  {
485  DragFinished( rDSDE.DropSuccess ? ( rDSDE.DropAction & ~DNDConstants::ACTION_DEFAULT ) : DNDConstants::ACTION_NONE );
486  ObjectReleased();
487  }
488  catch( const css::uno::Exception& )
489  {
490  }
491 }
492 
493 
494 void SAL_CALL TransferableHelper::dragEnter( const DragSourceDragEvent& )
495 {
496 }
497 
498 
499 void SAL_CALL TransferableHelper::dragExit( const DragSourceEvent& )
500 {
501 }
502 
503 
504 void SAL_CALL TransferableHelper::dragOver( const DragSourceDragEvent& )
505 {
506 }
507 
508 
509 void SAL_CALL TransferableHelper::dropActionChanged( const DragSourceDragEvent& )
510 {
511 }
512 
513 
515 {
516  sal_Int64 nRet;
517 
518  if( isUnoTunnelId<TransferableHelper>(rId) )
519  {
520  nRet = sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
521  }
522  else
523  nRet = 0;
524 
525  return nRet;
526 }
527 
528 
530 {
531  if( !mxClipboard.is() )
532  return;
533 
534  Reference< XFlushableClipboard > xFlushableClipboard( mxClipboard, UNO_QUERY );
535  SolarMutexReleaser aReleaser;
536 
537  try
538  {
539  if( xFlushableClipboard.is() )
540  xFlushableClipboard->flushClipboard();
541  }
542  catch( const css::uno::Exception& )
543  {
544  OSL_FAIL( "Could not flush clipboard" );
545  }
546 }
547 
548 
550 {
551  DataFlavor aFlavor;
552 
553  if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
554  AddFormat( aFlavor );
555 }
556 
557 
558 void TransferableHelper::AddFormat( const DataFlavor& rFlavor )
559 {
560  bool bAdd = true;
561 
562  for (auto & format : maFormats)
563  {
564  if( TransferableDataHelper::IsEqual( format, rFlavor ) )
565  {
566  // update MimeType for SotClipboardFormatId::OBJECTDESCRIPTOR in every case
567  if ((SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId) && mxObjDesc)
568  {
569  DataFlavor aObjDescFlavor;
570 
571  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDescFlavor );
572  format.MimeType = aObjDescFlavor.MimeType;
573  format.MimeType += ::ImplGetParameterString(*mxObjDesc);
574  }
575 
576  bAdd = false;
577  break;
578  }
579  }
580 
581  if( !bAdd )
582  return;
583 
584  DataFlavorEx aFlavorEx;
585 
586  aFlavorEx.MimeType = rFlavor.MimeType;
587  aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
588  aFlavorEx.DataType = rFlavor.DataType;
589  aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
590 
591  if ((SotClipboardFormatId::OBJECTDESCRIPTOR == aFlavorEx.mnSotId) && mxObjDesc)
592  aFlavorEx.MimeType += ::ImplGetParameterString(*mxObjDesc);
593 
594  maFormats.push_back(aFlavorEx);
595 
596  if( SotClipboardFormatId::BITMAP == aFlavorEx.mnSotId )
597  {
598  AddFormat( SotClipboardFormatId::PNG );
599  AddFormat( SotClipboardFormatId::BMP );
600  }
601  else if( SotClipboardFormatId::GDIMETAFILE == aFlavorEx.mnSotId )
602  {
603  AddFormat( SotClipboardFormatId::EMF );
604  AddFormat( SotClipboardFormatId::WMF );
605  }
606 }
607 
608 
610 {
611  DataFlavor aFlavor;
612 
613  if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
614  RemoveFormat( aFlavor );
615 }
616 
617 
618 void TransferableHelper::RemoveFormat( const DataFlavor& rFlavor )
619 {
620  DataFlavorExVector::iterator aIter(maFormats.begin());
621 
622  while (aIter != maFormats.end())
623  {
624  if( TransferableDataHelper::IsEqual( *aIter, rFlavor ) )
625  aIter = maFormats.erase(aIter);
626  else
627  ++aIter;
628  }
629 }
630 
631 
633 {
634  return std::any_of(maFormats.begin(), maFormats.end(),
635  [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
636 }
637 
638 
640 {
641  maFormats.clear();
642  maAny.clear();
643 }
644 
645 
646 bool TransferableHelper::SetAny( const Any& rAny )
647 {
648  maAny = rAny;
649  return maAny.hasValue();
650 }
651 
652 
653 bool TransferableHelper::SetString( const OUString& rString, const DataFlavor& rFlavor )
654 {
655  DataFlavor aFileFlavor;
656 
657  if( !rString.isEmpty() &&
658  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::SIMPLE_FILE, aFileFlavor ) &&
659  TransferableDataHelper::IsEqual( aFileFlavor, rFlavor ) )
660  {
661  const OString aByteStr(OUStringToOString(rString, osl_getThreadTextEncoding()));
662  Sequence< sal_Int8 > aSeq( aByteStr.getLength() + 1 );
663 
664  memcpy( aSeq.getArray(), aByteStr.getStr(), aByteStr.getLength() );
665  aSeq[ aByteStr.getLength() ] = 0;
666  maAny <<= aSeq;
667  }
668  else
669  maAny <<= rString;
670 
671  return maAny.hasValue();
672 }
673 
674 
675 bool TransferableHelper::SetBitmapEx( const BitmapEx& rBitmapEx, const DataFlavor& rFlavor )
676 {
677  if( !rBitmapEx.IsEmpty() )
678  {
679  SvMemoryStream aMemStm( 65535, 65535 );
680 
681  if(rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
682  {
683  // write a PNG
684  css::uno::Sequence<css::beans::PropertyValue> aFilterData;
685 
686 #ifdef IOS
687  // Use faster compression on slow devices
688  aFilterData.realloc(aFilterData.getLength() + 1);
689  aFilterData[aFilterData.getLength() - 1].Name = "Compression";
690 
691  // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed. For a
692  // typical 15 megapixel image from a DSLR, we are talking about a difference of 17 s for
693  // the default compression level vs 4 s for best speed, on an iPad Pro from 2017.
694  //
695  // Sure, the best would be to not have to re-encode the image at all, but have access to
696  // the original JPEG or PNG when there is a such.
697 
698  aFilterData[aFilterData.getLength() - 1].Value <<= 1;
699 #endif
700  vcl::PNGWriter aPNGWriter(rBitmapEx, &aFilterData);
701 
702  aPNGWriter.Write(aMemStm);
703  }
704  else
705  {
706  // explicitly use Bitmap::Write with bCompressed = sal_False and bFileHeader = sal_True
707  WriteDIB(rBitmapEx.GetBitmap(), aMemStm, false, true);
708  }
709 
710  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
711  }
712 
713  return maAny.hasValue();
714 }
715 
716 
718 {
719  if( rMtf.GetActionSize() )
720  {
721  SvMemoryStream aMemStm( 65535, 65535 );
722 
723  const_cast<GDIMetaFile&>(rMtf).Write( aMemStm );
724  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
725  }
726 
727  return maAny.hasValue();
728 }
729 
730 
732 {
733  if( rGraphic.GetType() != GraphicType::NONE )
734  {
735  SvMemoryStream aMemStm( 65535, 65535 );
736 
738  aMemStm.SetCompressMode( SvStreamCompressFlags::NATIVE );
739 
740  TypeSerializer aSerializer(aMemStm);
741  aSerializer.writeGraphic(rGraphic);
742 
743  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
744  }
745 
746  return maAny.hasValue();
747 }
748 
749 
751 {
752  SvMemoryStream aMemStm( 8192, 8192 );
753 
755  rIMap.Write( aMemStm );
756  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
757 
758  return maAny.hasValue();
759 }
760 
761 
763 {
764  PrepareOLE( rDesc );
765 
766  SvMemoryStream aMemStm( 1024, 1024 );
767 
768  WriteTransferableObjectDescriptor( aMemStm, rDesc );
769  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
770 
771  return maAny.hasValue();
772  }
773 
774 
776  const css::datatransfer::DataFlavor& rFlavor )
777 {
778  rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
779 
780  switch( SotExchange::GetFormat( rFlavor ) )
781  {
782  case SotClipboardFormatId::SOLK:
783  {
784  OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
785  OString sDesc(OUStringToOString(rBmk.GetDescription(), eSysCSet));
786  OStringBuffer sOut;
787  sOut.append(sURL.getLength());
788  sOut.append('@').append(sURL);
789  sOut.append(sDesc.getLength());
790  sOut.append('@').append(sDesc);
791 
792  Sequence< sal_Int8 > aSeq(sOut.getLength());
793  memcpy(aSeq.getArray(), sOut.getStr(), sOut.getLength());
794  maAny <<= aSeq;
795  }
796  break;
797 
798  case SotClipboardFormatId::STRING:
799  maAny <<= rBmk.GetURL();
800  break;
801 
802  case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
803  {
804  OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
805  Sequence< sal_Int8 > aSeq( sURL.getLength() );
806  memcpy( aSeq.getArray(), sURL.getStr(), sURL.getLength() );
807  maAny <<= aSeq;
808  }
809  break;
810 
811  case SotClipboardFormatId::NETSCAPE_BOOKMARK:
812  {
813  Sequence< sal_Int8 > aSeq( 2048 );
814 
815  memset( aSeq.getArray(), 0, 2048 );
816  strcpy( reinterpret_cast< char* >( aSeq.getArray() ), OUStringToOString(rBmk.GetURL(), eSysCSet).getStr() );
817  strcpy( reinterpret_cast< char* >( aSeq.getArray() ) + 1024, OUStringToOString(rBmk.GetDescription(), eSysCSet).getStr() );
818 
819  maAny <<= aSeq;
820  }
821  break;
822 
823 #ifdef _WIN32
824  case SotClipboardFormatId::FILEGRPDESCRIPTOR:
825  {
826  Sequence< sal_Int8 > aSeq( sizeof( FILEGROUPDESCRIPTOR ) );
827  FILEGROUPDESCRIPTOR* pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR*>(aSeq.getArray());
828  FILEDESCRIPTOR& rFDesc1 = pFDesc->fgd[ 0 ];
829 
830  pFDesc->cItems = 1;
831  memset( &rFDesc1, 0, sizeof( FILEDESCRIPTOR ) );
832  rFDesc1.dwFlags = FD_LINKUI;
833 
834  OStringBuffer aStr(OUStringToOString(
835  rBmk.GetDescription(), eSysCSet));
836  for( sal_Int32 nChar = 0; nChar < aStr.getLength(); ++nChar )
837  if( strchr( "\\/:*?\"<>|", aStr[nChar] ) )
838  aStr.remove(nChar--, 1);
839 
840  aStr.insert(0, "Shortcut to ");
841  aStr.append(".URL");
842  strcpy( rFDesc1.cFileName, aStr.getStr() );
843 
844  maAny <<= aSeq;
845  }
846  break;
847 
848  case SotClipboardFormatId::FILECONTENT:
849  {
850  maAny <<= "[InternetShortcut]\x0aURL=" + rBmk.GetURL();
851  }
852  break;
853 #endif
854 
855  default:
856  break;
857  }
858 
859  return maAny.hasValue();
860 }
861 
862 
864  const css::datatransfer::DataFlavor& rFlavor )
865 {
866  SvMemoryStream aMemStm( 1024, 1024 );
867 
869  rINtImg.Write( aMemStm, SotExchange::GetFormat( rFlavor ) );
870 
871  maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
872 
873  return maAny.hasValue();
874 }
875 
876 
877 bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
878 {
879  tools::SvRef<SotTempStream> xStm( new SotTempStream( OUString() ) );
880 
881  xStm->SetVersion( SOFFICE_FILEFORMAT_50 );
882 
883  if( pUserObject && WriteObject( xStm, pUserObject, nUserObjectId, rFlavor ) )
884  {
885  const sal_uInt32 nLen = xStm->TellEnd();
886  Sequence< sal_Int8 > aSeq( nLen );
887 
888  xStm->Seek( STREAM_SEEK_TO_BEGIN );
889  xStm->ReadBytes(aSeq.getArray(), nLen);
890 
891  if( nLen && ( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::STRING ) )
892  {
893  //JP 24.7.2001: as I know was this only for the writer application and this
894  // writes now UTF16 format into the stream
895  //JP 6.8.2001: and now it writes UTF8 because then exist no problem with
896  // little / big endians! - Bug 88121
897  maAny <<= OUString( reinterpret_cast< const char* >( aSeq.getConstArray() ), nLen - 1, RTL_TEXTENCODING_UTF8 );
898  }
899  else
900  maAny <<= aSeq;
901  }
902 
903  return maAny.hasValue();
904 }
905 
906 
907 bool TransferableHelper::WriteObject( tools::SvRef<SotTempStream>&, void*, sal_uInt32, const DataFlavor& )
908 {
909  OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
910  return false;
911 }
912 
913 
915 {
916 }
917 
918 
920 {
921 }
922 
923 
925 {
926  mxObjDesc.reset(new TransferableObjectDescriptor(rObjDesc));
927 
928  if( HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
929  AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
930 }
931 
932 void TransferableHelper::CopyToClipboard(const Reference<XClipboard>& rClipboard) const
933 {
934  if( rClipboard.is() )
935  mxClipboard = rClipboard;
936 
937  if( !mxClipboard.is() || mxTerminateListener.is() )
938  return;
939 
940  try
941  {
942  TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
943  pThis->mxTerminateListener = new TerminateListener( *pThis );
944  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
945  xDesktop->addTerminateListener( pThis->mxTerminateListener );
946 
947  mxClipboard->setContents( pThis, pThis );
948  }
949  catch( const css::uno::Exception& )
950  {
951  }
952 }
953 
955 {
956  DBG_ASSERT( pWindow, "Window pointer is NULL" );
957  Reference< XClipboard > xClipboard;
958 
959  if( pWindow )
960  xClipboard = pWindow->GetClipboard();
961 
962  CopyToClipboard(xClipboard);
963 }
964 
965 void TransferableHelper::CopyToSelection(const Reference<XClipboard>& rSelection) const
966 {
967  if( !rSelection.is() || mxTerminateListener.is() )
968  return;
969 
970  try
971  {
972  TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
973  pThis->mxTerminateListener = new TerminateListener( *pThis );
974  Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
975  xDesktop->addTerminateListener( pThis->mxTerminateListener );
976 
977  rSelection->setContents( pThis, pThis );
978  }
979  catch( const css::uno::Exception& )
980  {
981  }
982 }
983 
985 {
986  DBG_ASSERT( pWindow, "Window pointer is NULL" );
987  Reference< XClipboard > xSelection;
988 
989  if( pWindow )
990  xSelection = pWindow->GetPrimarySelection();
991 
992  CopyToSelection(xSelection);
993 }
994 
995 void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
996 
997 {
998  DBG_ASSERT( pWindow, "Window pointer is NULL" );
999  Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
1000 
1001  if( !xDragSource.is() )
1002  return;
1003 
1004  /*
1005  * #96792# release mouse before actually starting DnD.
1006  * This is necessary for the X11 DnD implementation to work.
1007  */
1008  if( pWindow->IsMouseCaptured() )
1009  pWindow->ReleaseMouse();
1010 
1011  const Point aPt( pWindow->GetPointerPosPixel() );
1012 
1013  // On macOS we are forced to execute 'startDrag' synchronously
1014  // contrary to the XDragSource interface specification because
1015  // we can receive drag events from the system only in the main
1016  // thread
1017 #if !defined(MACOSX)
1018  SolarMutexReleaser aReleaser;
1019 #endif
1020 
1021  try
1022  {
1023  DragGestureEvent aEvt;
1024  aEvt.DragAction = DNDConstants::ACTION_COPY;
1025  aEvt.DragOriginX = aPt.X();
1026  aEvt.DragOriginY = aPt.Y();
1027  aEvt.DragSource = xDragSource;
1028 
1029  xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
1030  }
1031  catch( const css::uno::Exception& )
1032  {
1033  }
1034 }
1035 
1037 {
1038  DBG_ASSERT( pWindow, "Window pointer is NULL" );
1039  Reference< XClipboard > xSelection( pWindow->GetPrimarySelection() );
1040 
1041  if( xSelection.is() )
1042  xSelection->setContents( nullptr, nullptr );
1043 }
1044 
1045 namespace
1046 {
1047  class theTransferableHelperUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theTransferableHelperUnoTunnelId > {};
1048 }
1049 
1051 {
1052  return theTransferableHelperUnoTunnelId::get().getSeq();
1053 }
1054 
1055 namespace {
1056 
1057 class TransferableClipboardNotifier : public ::cppu::WeakImplHelper< XClipboardListener >
1058 {
1059 private:
1060  ::osl::Mutex& mrMutex;
1061  Reference< XClipboardNotifier > mxNotifier;
1063 
1064 protected:
1065  // XClipboardListener
1066  virtual void SAL_CALL changedContents( const clipboard::ClipboardEvent& event ) override;
1067 
1068  // XEventListener
1069  virtual void SAL_CALL disposing( const EventObject& Source ) override;
1070 
1071 public:
1072  TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex );
1073 
1075  bool isListening() const { return mpListener != nullptr; }
1076 
1078  void dispose();
1079 };
1080 
1081 }
1082 
1083 TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
1084  :mrMutex( _rMutex )
1085  ,mxNotifier( _rxClipboard, UNO_QUERY )
1086  ,mpListener( &_rListener )
1087 {
1088  osl_atomic_increment( &m_refCount );
1089  {
1090  if ( mxNotifier.is() )
1091  mxNotifier->addClipboardListener( this );
1092  else
1093  // born dead
1094  mpListener = nullptr;
1095  }
1096  osl_atomic_decrement( &m_refCount );
1097 }
1098 
1099 
1100 void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
1101 {
1102  SolarMutexGuard aSolarGuard;
1103  // the SolarMutex here is necessary, since
1104  // - we cannot call mpListener without our own mutex locked
1105  // - Rebind respectively InitFormats (called by Rebind) will
1106  // try to lock the SolarMutex, too
1107  ::osl::MutexGuard aGuard( mrMutex );
1108  if( mpListener )
1109  mpListener->Rebind( event.Contents );
1110 }
1111 
1112 
1113 void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
1114 {
1115  // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1116  dispose();
1117 }
1118 
1119 
1120 void TransferableClipboardNotifier::dispose()
1121 {
1122  ::osl::MutexGuard aGuard( mrMutex );
1123 
1124  Reference< XClipboardListener > xKeepMeAlive( this );
1125 
1126  if ( mxNotifier.is() )
1127  mxNotifier->removeClipboardListener( this );
1128  mxNotifier.clear();
1129 
1130  mpListener = nullptr;
1131 }
1132 
1134 {
1135  ::osl::Mutex maMutex;
1137 
1139  {
1140  }
1141 };
1142 
1144  : mxObjDesc(new TransferableObjectDescriptor)
1145  , mxImpl(new TransferableDataHelper_Impl)
1146 {
1147 }
1148 
1149 TransferableDataHelper::TransferableDataHelper(const Reference< css::datatransfer::XTransferable >& rxTransferable)
1150  : mxTransfer(rxTransferable)
1151  , mxObjDesc(new TransferableObjectDescriptor)
1152  , mxImpl(new TransferableDataHelper_Impl)
1153 {
1154  InitFormats();
1155 }
1156 
1158  : mxTransfer(rDataHelper.mxTransfer)
1159  , mxClipboard(rDataHelper.mxClipboard)
1160  , maFormats(rDataHelper.maFormats)
1161  , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
1162  , mxImpl(new TransferableDataHelper_Impl)
1163 {
1164 }
1165 
1167  : mxTransfer(std::move(rDataHelper.mxTransfer))
1168  , mxClipboard(std::move(rDataHelper.mxClipboard))
1169  , maFormats(std::move(rDataHelper.maFormats))
1170  , mxObjDesc(std::move(rDataHelper.mxObjDesc))
1171  , mxImpl(new TransferableDataHelper_Impl)
1172 {
1173 }
1174 
1176 {
1177  if ( this != &rDataHelper )
1178  {
1179  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1180 
1181  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1182 
1183  if (bWasClipboardListening)
1185 
1186  mxTransfer = rDataHelper.mxTransfer;
1187  maFormats = rDataHelper.maFormats;
1188  mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
1189  mxClipboard = rDataHelper.mxClipboard;
1190 
1191  if (bWasClipboardListening)
1193  }
1194 
1195  return *this;
1196 }
1197 
1199 {
1200  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1201 
1202  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1203 
1204  if (bWasClipboardListening)
1206 
1207  mxTransfer = std::move(rDataHelper.mxTransfer);
1208  maFormats = std::move(rDataHelper.maFormats);
1209  mxObjDesc = std::move(rDataHelper.mxObjDesc);
1210  mxClipboard = std::move(rDataHelper.mxClipboard);
1211 
1212  if (bWasClipboardListening)
1214 
1215  return *this;
1216 }
1217 
1219 {
1221  {
1222  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1223  maFormats.clear();
1224  mxObjDesc.reset();
1225  }
1226 }
1227 
1228 void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
1229  DataFlavorExVector& rDataFlavorExVector )
1230 {
1231  try
1232  {
1234  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
1235  DataFlavorEx aFlavorEx;
1236  const OUString aCharsetStr( "charset" );
1237 
1238 
1239  for (auto const& rFlavor : rDataFlavorSeq)
1240  {
1241  Reference< XMimeContentType > xMimeType;
1242 
1243  try
1244  {
1245  if( !rFlavor.MimeType.isEmpty() )
1246  xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
1247  }
1248  catch( const css::uno::Exception& )
1249  {
1250  }
1251 
1252  aFlavorEx.MimeType = rFlavor.MimeType;
1253  aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
1254  aFlavorEx.DataType = rFlavor.DataType;
1255  aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
1256 
1257  rDataFlavorExVector.push_back( aFlavorEx );
1258 
1259  // add additional formats for special mime types
1260  if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId || SotClipboardFormatId::JPEG == aFlavorEx.mnSotId)
1261  {
1262  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
1263  {
1264  aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
1265  rDataFlavorExVector.push_back( aFlavorEx );
1266  }
1267  }
1268  else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
1269  {
1270  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
1271  {
1272  aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
1273  rDataFlavorExVector.push_back( aFlavorEx );
1274  }
1275  }
1276  else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
1277  {
1278  // #104735# HTML_SIMPLE may also be inserted without comments
1279  aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
1280  rDataFlavorExVector.push_back( aFlavorEx );
1281  }
1282  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
1283  {
1284  // add, if it is a UTF-8 byte buffer
1285  if( xMimeType->hasParameter( aCharsetStr ) )
1286  {
1287  if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
1288  xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
1289  {
1290  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
1291 
1292  }
1293  }
1294  }
1295  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
1296  {
1297  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
1298  }
1299  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
1300  {
1301  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
1302  }
1303  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
1304 
1305  {
1306  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
1307  }
1308  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
1309  {
1310  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
1311  }
1312  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
1313  {
1314  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
1315  }
1316  }
1317  }
1318  catch( const css::uno::Exception& )
1319  {
1320  }
1321 }
1322 
1324 {
1325  SolarMutexGuard aSolarGuard;
1326  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1327 
1328  maFormats.clear();
1330 
1331  if( !mxTransfer.is() )
1332  return;
1333 
1335 
1336  for (auto const& format : maFormats)
1337  {
1338  if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
1339  {
1341  break;
1342  }
1343  }
1344 }
1345 
1346 
1348 {
1349  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1350  return std::any_of(maFormats.begin(), maFormats.end(),
1351  [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
1352 }
1353 
1354 bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
1355 {
1356  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1357  for (auto const& format : maFormats)
1358  {
1359  if( TransferableDataHelper::IsEqual( rFlavor, format ) )
1360  return true;
1361  }
1362 
1363  return false;
1364 }
1365 
1367 {
1368  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1369  return maFormats.size();
1370 }
1371 
1373 {
1374  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1375  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1376  return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
1377 }
1378 
1379 DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
1380 {
1381  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1382  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1383 
1384  DataFlavor aRet;
1385 
1386  if (nFormat < maFormats.size())
1387  aRet = maFormats[nFormat];
1388 
1389  return aRet;
1390 }
1391 
1392 
1393 Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
1394 {
1395  Reference< XTransferable > xRet;
1396 
1397  if( mxTransfer.is() )
1398  {
1399  try
1400  {
1401  xRet = mxTransfer;
1402 
1403  // do a dummy call to check, if this interface is valid (nasty)
1404  xRet->getTransferDataFlavors();
1405 
1406  }
1407  catch( const css::uno::Exception& )
1408  {
1409  xRet.clear();
1410  }
1411  }
1412 
1413  return xRet;
1414 }
1415 
1416 
1417 Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
1418 {
1419  Any aReturn;
1420 
1421  DataFlavor aFlavor;
1422  if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
1423  aReturn = GetAny(aFlavor, rDestDoc);
1424 
1425  return aReturn;
1426 }
1427 
1428 Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
1429 {
1430  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1431  Any aRet;
1432 
1433  try
1434  {
1435  if( mxTransfer.is() )
1436  {
1437  const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
1438 
1439  Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
1440 
1441  if( nRequestFormat != SotClipboardFormatId::NONE )
1442  {
1443  // try to get alien format first
1444  for (auto const& format : maFormats)
1445  {
1446  if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
1447  {
1448 // tdf#133365: only release solar mutex on Windows
1449 #ifdef _WIN32
1450  // tdf#133527: first, make sure that we actually hold the mutex
1451  SolarMutexGuard g;
1452  // Our own thread may handle the nested IDataObject::GetData call,
1453  // and try to acquire solar mutex
1455 #endif // _WIN32
1456 
1457  if (xTransfer2.is())
1458  aRet = xTransfer2->getTransferData2(format, rDestDoc);
1459  else
1460  aRet = mxTransfer->getTransferData(format);
1461  }
1462 
1463  if( aRet.hasValue() )
1464  break;
1465  }
1466  }
1467 
1468  if( !aRet.hasValue() )
1469  {
1470 // tdf#133365: only release solar mutex on Windows
1471 #ifdef _WIN32
1472  // tdf#133527: first, make sure that we actually hold the mutex
1473  SolarMutexGuard g;
1474  // Our own thread may handle the nested IDataObject::GetData call,
1475  // and try to acquire solar mutex
1477 #endif // _WIN32
1478 
1479  if (xTransfer2.is())
1480  aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
1481  else
1482  aRet = mxTransfer->getTransferData(rFlavor);
1483  }
1484  }
1485  }
1486  catch( const css::uno::Exception& )
1487  {
1488  }
1489 
1490  return aRet;
1491 }
1492 
1493 
1495 {
1496  DataFlavor aFlavor;
1497  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
1498 }
1499 
1500 
1501 bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr )
1502 {
1503  Any aAny = GetAny(rFlavor, OUString());
1504  bool bRet = false;
1505 
1506  if( aAny.hasValue() )
1507  {
1508  OUString aOUString;
1510 
1511  if( aAny >>= aOUString )
1512  {
1513  rStr = aOUString;
1514  bRet = true;
1515  }
1516  else if( aAny >>= aSeq )
1517  {
1518 
1519  const char* pChars = reinterpret_cast< const char* >( aSeq.getConstArray() );
1520  sal_Int32 nLen = aSeq.getLength();
1521 
1522  //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
1523  //DVO 2002-05-27: strip _all_ trailing zeros
1524  while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
1525  --nLen;
1526 
1527  rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
1528  bRet = true;
1529  }
1530  }
1531 
1532  return bRet;
1533 }
1534 
1535 
1537 {
1538  if(SotClipboardFormatId::BITMAP == nFormat)
1539  {
1540  // try to get PNG first
1541  DataFlavor aFlavor;
1542 
1543  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1544  {
1545  if(GetBitmapEx(aFlavor, rBmpEx))
1546  {
1547  return true;
1548  }
1549  }
1550 
1551  // then JPEG
1552  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor))
1553  {
1554  if(GetBitmapEx(aFlavor, rBmpEx))
1555  {
1556  return true;
1557  }
1558  }
1559  }
1560 
1561  DataFlavor aFlavor;
1562  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
1563 }
1564 
1565 
1566 bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx )
1567 {
1569  DataFlavor aSubstFlavor;
1570  bool bRet(GetSotStorageStream(rFlavor, xStm));
1571  bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
1572  bool bSuppressJPEG(false);
1573 
1574  if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
1575  {
1576  // when no direct success, try if PNG is available
1577  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1578  bSuppressJPEG = bRet;
1579  }
1580 
1581  if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
1582  {
1583  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1584  bSuppressPNG = bRet;
1585  }
1586 
1587  if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
1588  {
1589  // when no direct success, try if BMP is available
1590  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1591  bSuppressPNG = bRet;
1592  bSuppressJPEG = bRet;
1593  }
1594 
1595  if(bRet)
1596  {
1597  if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
1598  {
1599  // it's a PNG, import to BitmapEx
1600  vcl::PNGReader aPNGReader(*xStm);
1601 
1602  rBmpEx = aPNGReader.Read();
1603  }
1604  else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
1605  {
1606  // it's a JPEG, import to BitmapEx
1608  Graphic aGraphic;
1609  if (rFilter.ImportGraphic(aGraphic, "", *xStm) == ERRCODE_NONE)
1610  rBmpEx = aGraphic.GetBitmapEx();
1611  }
1612 
1613  if(rBmpEx.IsEmpty())
1614  {
1615  Bitmap aBitmap;
1616  AlphaMask aMask;
1617 
1618  // explicitly use Bitmap::Read with bFileHeader = sal_True
1619  // #i124085# keep DIBV5 for read from clipboard, but should not happen
1620  ReadDIBV5(aBitmap, aMask, *xStm);
1621 
1622  if(aMask.GetBitmap().IsEmpty())
1623  {
1624  rBmpEx = aBitmap;
1625  }
1626  else
1627  {
1628  rBmpEx = BitmapEx(aBitmap, aMask);
1629  }
1630  }
1631 
1632  bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
1633 
1634  /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
1635  problem is, that some graphics are inserted much too big because the nXPelsPerMeter
1636  and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
1637  Due to this reason the following code assumes that bitmaps with a logical size
1638  greater than 50 cm aren't having the correct mapmode set.
1639 
1640  The following code should be removed if DDBs and DIBs are supported via clipboard
1641  properly.
1642  */
1643  if(bRet)
1644  {
1645  const MapMode aMapMode(rBmpEx.GetPrefMapMode());
1646 
1647  if(MapUnit::MapPixel != aMapMode.GetMapUnit())
1648  {
1649  const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
1650 
1651  // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
1652  // the described 50 cm (which is 50000 100th mm)
1653  if((aSize.Width() > 50000) || (aSize.Height() > 50000))
1654  {
1655  rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
1656 
1657  // #i122388# also adapt size by applying the mew MapMode
1658  const Size aNewSize(OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel)));
1659  rBmpEx.SetPrefSize(aNewSize);
1660  }
1661  }
1662  }
1663  }
1664 
1665  return bRet;
1666 }
1667 
1668 
1670 {
1671  DataFlavor aFlavor;
1672  return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
1673  GetGDIMetaFile(aFlavor, rMtf) &&
1674  (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
1675 }
1676 
1677 
1678 bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf )
1679 {
1681  DataFlavor aSubstFlavor;
1682  bool bRet = false;
1683 
1684  if( GetSotStorageStream( rFlavor, xStm ) )
1685  {
1686  ReadGDIMetaFile( *xStm, rMtf );
1687  bRet = ( xStm->GetError() == ERRCODE_NONE );
1688  }
1689 
1690  if( !bRet &&
1691  HasFormat( SotClipboardFormatId::EMF ) &&
1692  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
1693  GetSotStorageStream( aSubstFlavor, xStm ) )
1694  {
1695  Graphic aGraphic;
1696 
1697  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1698  {
1699  rMtf = aGraphic.GetGDIMetaFile();
1700  bRet = true;
1701  }
1702  }
1703 
1704  if( !bRet &&
1705  HasFormat( SotClipboardFormatId::WMF ) &&
1706  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
1707  GetSotStorageStream( aSubstFlavor, xStm ) )
1708  {
1709  Graphic aGraphic;
1710 
1711  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1712  {
1713  rMtf = aGraphic.GetGDIMetaFile();
1714  bRet = true;
1715  }
1716  }
1717 
1718  return bRet;
1719 }
1720 
1721 
1723 {
1724  if(SotClipboardFormatId::BITMAP == nFormat)
1725  {
1726  // try to get PNG first
1727  DataFlavor aFlavor;
1728 
1729  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1730  {
1731  if(GetGraphic(aFlavor, rGraphic))
1732  {
1733  return true;
1734  }
1735  }
1736  }
1737 
1738  DataFlavor aFlavor;
1739  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
1740 }
1741 
1742 
1743 bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic )
1744 {
1745  DataFlavor aFlavor;
1746  bool bRet = false;
1747 
1748  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
1749  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1750  {
1751  // try to get PNG first
1752  BitmapEx aBmpEx;
1753 
1754  bRet = GetBitmapEx( aFlavor, aBmpEx );
1755  if( bRet )
1756  rGraphic = aBmpEx;
1757  }
1758  else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
1759  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1760  {
1761  Graphic aGraphic;
1763  if (GetSotStorageStream(rFlavor, xStm))
1764  {
1765  if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
1766  {
1767  rGraphic = aGraphic;
1768  bRet = true;
1769  }
1770  }
1771  }
1772  else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1773  {
1774  BitmapEx aBitmapEx;
1775 
1776  bRet = GetBitmapEx(aFlavor, aBitmapEx);
1777  if (bRet)
1778  rGraphic = aBitmapEx;
1779  }
1780  else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
1781  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1782  {
1783  BitmapEx aBmpEx;
1784 
1785  bRet = GetBitmapEx( aFlavor, aBmpEx );
1786  if( bRet )
1787  rGraphic = aBmpEx;
1788  }
1789  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
1790  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1791  {
1792  GDIMetaFile aMtf;
1793 
1794  bRet = GetGDIMetaFile( aFlavor, aMtf );
1795  if( bRet )
1796  rGraphic = aMtf;
1797  }
1798  else
1799  {
1801 
1802  if( GetSotStorageStream( rFlavor, xStm ) )
1803  {
1804  TypeSerializer aSerializer(*xStm);
1805  aSerializer.readGraphic(rGraphic);
1806  bRet = ( xStm->GetError() == ERRCODE_NONE );
1807  }
1808  }
1809 
1810  return bRet;
1811 }
1812 
1813 
1815 {
1816  DataFlavor aFlavor;
1817  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
1818 }
1819 
1820 
1821 bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap )
1822 {
1824  bool bRet = GetSotStorageStream( rFlavor, xStm );
1825 
1826  if( bRet )
1827  {
1828  rIMap.Read( *xStm );
1829  bRet = ( xStm->GetError() == ERRCODE_NONE );
1830  }
1831 
1832  return bRet;
1833 }
1834 
1835 
1837 {
1838  DataFlavor aFlavor;
1839  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
1840 }
1841 
1842 
1844 {
1845  rDesc = *mxObjDesc;
1846  return true;
1847 }
1848 
1849 
1851 {
1852  DataFlavor aFlavor;
1853  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
1854 }
1855 
1856 
1857 bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk )
1858 {
1859  bool bRet = false;
1860  if( HasFormat( rFlavor ))
1861  {
1862  const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
1863  switch( nFormat )
1864  {
1865  case SotClipboardFormatId::SOLK:
1866  case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
1867  {
1868  OUString aString;
1869  if( GetString( rFlavor, aString ) )
1870  {
1871  if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
1872  {
1873  rBmk = INetBookmark( aString, aString );
1874  bRet = true;
1875  }
1876  else
1877  {
1878  OUString aURL, aDesc;
1879  sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
1880 
1881  if( !nLen && aString[ 0 ] != '0' )
1882  {
1883  SAL_INFO( "svtools", "SOLK: 1. len=0" );
1884  }
1885  if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
1886  {
1887  SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
1888  }
1889  aURL = aString.copy( nStart + 1, nLen );
1890 
1891  aString = aString.replaceAt( 0, nStart + 1 + nLen, "" );
1892  nStart = aString.indexOf( '@' );
1893  nLen = aString.toInt32();
1894 
1895  if( !nLen && aString[ 0 ] != '0' )
1896  {
1897  SAL_INFO( "svtools", "SOLK: 2. len=0" );
1898  }
1899  if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
1900  {
1901  SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
1902  }
1903  aDesc = aString.copy( nStart+1, nLen );
1904 
1905  rBmk = INetBookmark( aURL, aDesc );
1906  bRet = true;
1907  }
1908  }
1909  }
1910  break;
1911 
1912  case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1913  {
1914  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1915 
1916  if (2048 == aSeq.getLength())
1917  {
1918  const char* p1 = reinterpret_cast< const char* >( aSeq.getConstArray() );
1919  const char* p2 = reinterpret_cast< const char* >( aSeq.getConstArray() ) + 1024;
1920  rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
1921  OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
1922  bRet = true;
1923  }
1924  }
1925  break;
1926 
1927 #ifdef _WIN32
1928  case SotClipboardFormatId::FILEGRPDESCRIPTOR:
1929  {
1930  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1931 
1932  if (aSeq.getLength())
1933  {
1934  FILEGROUPDESCRIPTOR const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR const *>(aSeq.getConstArray());
1935 
1936  if( pFDesc->cItems )
1937  {
1938  OString aDesc( pFDesc->fgd[ 0 ].cFileName );
1939  rtl_TextEncoding eTextEncoding = osl_getThreadTextEncoding();
1940 
1941  if( ( aDesc.getLength() > 4 ) && aDesc.copy(aDesc.getLength() - 4).equalsIgnoreAsciiCase(".URL") )
1942  {
1943  std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( OStringToOUString(aDesc, eTextEncoding) ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1944  StreamMode::STD_READ ));
1945 
1946  if( !pStream || pStream->GetError() )
1947  {
1948  DataFlavor aFileContentFlavor;
1949 
1950  aSeq.realloc( 0 );
1951  pStream.reset();
1952 
1953  if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
1954  {
1955  aSeq = GetSequence(aFileContentFlavor, OUString());
1956  if (aSeq.getLength())
1957  pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
1958  }
1959  }
1960 
1961  if( pStream )
1962  {
1963  OString aLine;
1964  bool bSttFnd = false;
1965 
1966  while( pStream->ReadLine( aLine ) )
1967  {
1968  if (aLine.equalsIgnoreAsciiCase("[InternetShortcut]"))
1969  bSttFnd = true;
1970  else if (bSttFnd && aLine.copy(0, 4).equalsIgnoreAsciiCase("URL="))
1971  {
1972  rBmk = INetBookmark( OStringToOUString(aLine.subView(4), eTextEncoding),
1973  OStringToOUString(aDesc.subView(0, aDesc.getLength() - 4), eTextEncoding) );
1974  bRet = true;
1975  break;
1976  }
1977  }
1978  }
1979  }
1980  }
1981  }
1982  }
1983  break;
1984 #endif
1985  default: break;
1986  }
1987  }
1988  return bRet;
1989 }
1990 
1991 
1993  INetImage& rINtImg )
1994 {
1995  DataFlavor aFlavor;
1996  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
1997 }
1998 
1999 
2001  const css::datatransfer::DataFlavor& rFlavor,
2002  INetImage& rINtImg )
2003 {
2005  bool bRet = GetSotStorageStream( rFlavor, xStm );
2006 
2007  if( bRet )
2008  bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
2009  return bRet;
2010 }
2011 
2012 
2014  FileList& rFileList )
2015 {
2016  DataFlavor aFlavor;
2017  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
2018 }
2019 
2020 
2022 {
2024  bool bRet = false;
2025 
2026  for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
2027  {
2028  if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
2029  {
2030  const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
2031 
2032  if( GetSotStorageStream( aFlavor, xStm ) )
2033  {
2034  if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
2035  {
2036  OString aDiskString;
2037 
2038  while( xStm->ReadLine( aDiskString ) )
2039  if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
2040  rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
2041 
2042  bRet = true;
2043  }
2044  else
2045  bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
2046  }
2047  }
2048  }
2049 
2050  return bRet;
2051 }
2052 
2053 
2054 Sequence<sal_Int8> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat, const OUString& rDestDoc )
2055 {
2056  DataFlavor aFlavor;
2057  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2058  return Sequence<sal_Int8>();
2059 
2060  return GetSequence(aFlavor, rDestDoc);
2061 }
2062 
2063 Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc )
2064 {
2065  const Any aAny = GetAny(rFlavor, rDestDoc);
2066  Sequence<sal_Int8> aSeq;
2067  if (aAny.hasValue())
2068  aAny >>= aSeq;
2069 
2070  return aSeq;
2071 }
2072 
2073 
2075 {
2076  DataFlavor aFlavor;
2077  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
2078 }
2079 
2080 
2081 bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotTempStream>& rxStream )
2082 {
2083  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
2084 
2085  if (aSeq.hasElements())
2086  {
2087  rxStream = new SotTempStream( "" );
2088  rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
2089  rxStream->Seek( 0 );
2090  }
2091 
2092  return aSeq.hasElements();
2093 }
2094 
2096 {
2097  DataFlavor aFlavor;
2098  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2099  return Reference<XInputStream>();
2100 
2101  return GetInputStream(aFlavor, rDestDoc);
2102 }
2103 
2104 Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc )
2105 {
2106  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
2107 
2108  if (!aSeq.hasElements())
2109  return Reference<XInputStream>();
2110 
2112  return xStream;
2113 }
2114 
2115 void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
2116 {
2117  mxTransfer = _rxNewContent;
2118  InitFormats();
2119 }
2120 
2122 {
2123  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2124 
2126 
2127  mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
2128 
2129  return mxImpl->mxClipboardListener->isListening();
2130 }
2131 
2133 {
2134  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2135 
2136  if (mxImpl->mxClipboardListener.is())
2137  {
2138  mxImpl->mxClipboardListener->dispose();
2139  mxImpl->mxClipboardListener.clear();
2140  }
2141 }
2142 
2143 TransferableDataHelper TransferableDataHelper::CreateFromClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& rClipboard)
2144 {
2146 
2147  if( rClipboard.is() )
2148  {
2149  try
2150  {
2151  Reference< XTransferable > xTransferable( rClipboard->getContents() );
2152 
2153  if( xTransferable.is() )
2154  {
2155  aRet = TransferableDataHelper( xTransferable );
2156  // also copy the clipboard
2157  aRet.mxClipboard = rClipboard;
2158  }
2159  }
2160  catch( const css::uno::Exception& )
2161  {
2162  }
2163  }
2164 
2165  return aRet;
2166 }
2167 
2169 {
2170  DBG_ASSERT( pWindow, "Window pointer is NULL" );
2171 
2172  Reference< XClipboard > xClipboard;
2173 
2174  if( pWindow )
2175  xClipboard = pWindow->GetClipboard();
2176 
2177  return CreateFromClipboard(xClipboard);
2178 }
2179 
2180 
2182 {
2183  DBG_ASSERT( pWindow, "Window pointer is NULL" );
2184 
2185  Reference< XClipboard > xSelection;
2187 
2188  if( pWindow )
2189  xSelection = pWindow->GetPrimarySelection();
2190 
2191  if( xSelection.is() )
2192  {
2193  SolarMutexReleaser aReleaser;
2194 
2195  try
2196  {
2197  Reference< XTransferable > xTransferable( xSelection->getContents() );
2198 
2199  if( xTransferable.is() )
2200  {
2201  aRet = TransferableDataHelper( xTransferable );
2202  aRet.mxClipboard = xSelection;
2203  }
2204  }
2205  catch( const css::uno::Exception& )
2206  {
2207  }
2208  }
2209 
2210  return aRet;
2211 }
2212 
2213 
2214 bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
2215  const css::datatransfer::DataFlavor& rRequestFlavor )
2216 {
2218  bool bRet = false;
2219 
2220  try
2221  {
2222  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
2223 
2224  Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
2225  Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
2226 
2227  if( xRequestType1.is() && xRequestType2.is() )
2228  {
2229  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
2230  {
2231  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
2232  {
2233  // special handling for text/plain media types
2234  const OUString aCharsetString( "charset" );
2235 
2236  if( !xRequestType2->hasParameter( aCharsetString ) ||
2237  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
2238  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
2239  {
2240  bRet = true;
2241  }
2242  }
2243  else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
2244  {
2245  // special handling for application/x-openoffice media types
2246  const OUString aFormatString( "windows_formatname" );
2247 
2248  if( xRequestType1->hasParameter( aFormatString ) &&
2249  xRequestType2->hasParameter( aFormatString ) &&
2250  xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
2251  {
2252  bRet = true;
2253  }
2254  }
2255  else
2256  bRet = true;
2257  }
2258  }
2259  }
2260  catch( const css::uno::Exception& )
2261  {
2262  bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
2263  }
2264 
2265  return bRet;
2266 }
2267 
2268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool GetGraphic(SotClipboardFormatId nFormat, Graphic &rGraphic)
Definition: transfer.cxx:1722
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: transfer.cxx:243
bool SetINetImage(const INetImage &rINtImg, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:863
css::uno::Reference< css::datatransfer::dnd::XDragSource > GetDragSource()
Definition: mouse.cxx:719
Point GetPointerPosPixel()
Definition: mouse.cxx:550
VCL_DLLPRIVATE void ImplFlush()
Definition: transfer.cxx:529
URL aURL
void Write(SvStream &rOStm) const
Definition: imap.cxx:919
bool GetSotStorageStream(SotClipboardFormatId nFormat, tools::SvRef< SotTempStream > &rStreamRef)
Definition: transfer.cxx:2074
ErrCode ImportGraphic(Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat=GRFILTER_FORMAT_DONTKNOW, sal_uInt16 *pDeterminedFormat=nullptr, GraphicFilterImportFlags nImportFlags=GraphicFilterImportFlags::NONE)
css::uno::Reference< css::frame::XTerminateListener > mxTerminateListener
Definition: transfer.hxx:170
css::uno::Any GetAny(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:1417
bool SetBitmapEx(const BitmapEx &rBitmap, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:675
void readGraphic(Graphic &rGraphic)
void setWidth(tools::Long nWidth)
SvStream & WriteInt32(sal_Int32 nInt32)
virtual sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:427
const MapMode & GetPrefMapMode() const
Definition: bitmapex.hxx:90
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1502
virtual void SAL_CALL dragOver(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:504
virtual void AddSupportedFormats()=0
signed char sal_Int8
css::uno::Reference< css::datatransfer::clipboard::XClipboard > GetClipboard()
Definition: window.cxx:3428
OUString maLastFormat
Definition: transfer.hxx:168
Bitmap const & GetBitmap() const
Definition: alpha.cxx:73
void Rebind(const css::uno::Reference< css::datatransfer::XTransferable > &_rxNewData)
Definition: transfer.cxx:2115
::std::vector< DataFlavorEx > DataFlavorExVector
void SetPrefMapMode(const MapMode &rPrefMapMode)
Definition: bitmapex.hxx:91
bool ConvertGDIMetaFileToWMF(const GDIMetaFile &rMTF, SvStream &rTargetStream, FilterConfigItem const *pConfigItem, bool bPlaceable)
Definition: wmf.cxx:70
bool SetTransferableObjectDescriptor(const TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:762
bool HasFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:632
DataFlavorExVector maFormats
Definition: transfer.hxx:282
#define STREAM_SEEK_TO_END
sal_uInt64 Seek(sal_uInt64 nPos)
Class to import and export graphic formats.
SotClipboardFormatId GetFormat(sal_uInt32 nFormat) const
Definition: transfer.cxx:1372
virtual void DragFinished(sal_Int8 nDropAction)
Definition: transfer.cxx:914
bool GetINetBookmark(SotClipboardFormatId nFormat, INetBookmark &rBmk)
Definition: transfer.cxx:1850
virtual sal_Bool SAL_CALL isComplex() override
Definition: transfer.cxx:403
bool HasFormat(SotClipboardFormatId nFormat) const
Definition: transfer.cxx:1347
sal_uInt64 SeekRel(sal_Int64 nPos)
bool SetINetBookmark(const INetBookmark &rBmk, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:775
bool SetObject(void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:877
virtual sal_uInt64 TellEnd() override
void AddFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:549
SvStream & WriteTransferableObjectDescriptor(SvStream &rOStm, const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:82
virtual ~TerminateListener() override
Definition: transfer.cxx:238
sal_uInt16 sal_Unicode
virtual OUString SAL_CALL getImplementationName() override
Definition: transfer.cxx:258
ErrCode GetError() const
Reference< XInputStream > xStream
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
DataFlavorExVector maFormats
Definition: transfer.hxx:171
const Size & GetPrefSize() const
Definition: bitmapex.hxx:87
A helper class that calls Application::ReleaseSolarMutex() in its constructor and restores the mutex ...
Definition: svapp.hxx:1416
css::uno::Reference< css::datatransfer::clipboard::XClipboard > GetPrimarySelection()
Definition: window.cxx:3437
IntrinsicAnimationEventHandlerSharedPtr mpListener
SvStream & WriteUniOrByteString(const OUString &rStr, rtl_TextEncoding eDestCharSet)
static TransferableDataHelper CreateFromSystemClipboard(vcl::Window *pWindow)
Definition: transfer.cxx:2168
const GDIMetaFile & GetGDIMetaFile() const
Definition: graph.cxx:335
SvStream & WriteUInt32(sal_uInt32 nUInt32)
virtual css::uno::Any SAL_CALL getTransferData2(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc) override
Definition: transfer.cxx:291
TransferableDataHelper & operator=(const TransferableDataHelper &rDataHelper)
Definition: transfer.cxx:1175
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: transfer.cxx:268
virtual bool WriteObject(tools::SvRef< SotTempStream > &rxOStm, void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:907
SotClipboardFormatId
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
std::unique_ptr< TransferableDataHelper_Impl > mxImpl
Definition: transfer.hxx:284
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:283
virtual void SAL_CALL dragEnter(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:494
virtual void SAL_CALL dropActionChanged(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:509
static void ImplSetParameterString(TransferableObjectDescriptor &rObjDesc, const DataFlavorEx &rFlavorEx)
Definition: transfer.cxx:162
static bool IsEqual(const css::datatransfer::DataFlavor &rInternalFlavor, const css::datatransfer::DataFlavor &rRequestFlavor)
Definition: transfer.cxx:2214
bool SetGraphic(const Graphic &rGraphic)
Definition: transfer.cxx:731
bool IsEmpty() const
Definition: BitmapEx.cxx:198
bool GetINetImage(SotClipboardFormatId nFormat, INetImage &rINtImg)
Definition: transfer.cxx:1992
void RemoveFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:609
#define SOFFICE_FILEFORMAT_50
#define DBG_ASSERT(sCon, aError)
css::datatransfer::DataFlavor GetFormatDataFlavor(sal_uInt32 nFormat) const
Definition: transfer.cxx:1379
int i
TerminateListener(TransferableHelper &rDropTargetHelper)
Definition: transfer.cxx:232
GraphicType GetType() const
Definition: graph.cxx:289
OUString GetHexName() const
#define STREAM_SEEK_TO_BEGIN
css::uno::Reference< css::datatransfer::XTransferable > GetXTransferable() const
Definition: transfer.cxx:1393
virtual void SAL_CALL queryTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:248
bool GetString(SotClipboardFormatId nFormat, OUString &rStr)
Definition: transfer.cxx:1494
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
Definition: transfer.cxx:1050
SvStream & ReadFileList(SvStream &rIStm, FileList &rFileList)
virtual sal_Bool SAL_CALL supportsService(const OUString &sServiceName) override
Definition: transfer.cxx:263
virtual void SAL_CALL notifyTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:253
tools::Long Width() const
#define TOD_SIG1
Definition: transfer.cxx:79
sal_uInt32 GetFormatCount() const
Definition: transfer.cxx:1366
unsigned char sal_Bool
bool Write(SvStream &rStream)
Definition: pngwrite.cxx:707
const OUString & GetDescription() const
void PrepareOLE(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:924
bool IsMouseCaptured() const
Definition: mouse.cxx:469
void StartDrag(vcl::Window *pWindow, sal_Int8 nDragSourceActions)
Definition: transfer.cxx:995
bool ReadDIBV5(Bitmap &rTarget, AlphaMask &rTargetAlpha, SvStream &rIStm)
Definition: dibtools.cxx:1842
static void ClearSelection(vcl::Window *pWindow)
Definition: transfer.cxx:1036
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:325
void CopyToClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
void SetVersion(sal_Int32 n)
void AppendFile(const OUString &rStr)
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:172
static ErrCode Import(SvStream &rIStm, Graphic &rGraphic, ConvertDataFormat nFormat=ConvertDataFormat::Unknown)
Definition: cvtgrf.cxx:34
virtual void SAL_CALL dragExit(const css::datatransfer::dnd::DragSourceEvent &dse) override
Definition: transfer.cxx:499
exports com.sun.star.chart2. data
virtual void SAL_CALL dragDropEnd(const css::datatransfer::dnd::DragSourceDropEvent &dsde) override
Definition: transfer.cxx:479
bool GetImageMap(SotClipboardFormatId nFormat, ImageMap &rIMap)
Definition: transfer.cxx:1814
virtual void SAL_CALL lostOwnership(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &xClipboard, const css::uno::Reference< css::datatransfer::XTransferable > &xTrans) override
Definition: transfer.cxx:452
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:231
virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 > &rId) override
Definition: transfer.cxx:514
void ReleaseMouse()
Definition: mouse.cxx:458
#define TOD_SIG2
Definition: transfer.cxx:80
bool GetGDIMetaFile(SotClipboardFormatId nFormat, GDIMetaFile &rMtf, size_t nMaxActions=0)
Return as GDI metafile.
Definition: transfer.cxx:1669
virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override
Definition: transfer.cxx:410
static ErrCode Export(SvStream &rOStm, const Graphic &rGraphic, ConvertDataFormat nFormat)
Definition: cvtgrf.cxx:55
static SotClipboardFormatId RegisterFormat(const css::datatransfer::DataFlavor &rFlavor)
bool SetImageMap(const ImageMap &rIMap)
Definition: transfer.cxx:750
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:169
static SotClipboardFormatId GetFormat(const css::datatransfer::DataFlavor &rFlavor)
static void FillDataFlavorExVector(const css::uno::Sequence< css::datatransfer::DataFlavor > &rDataFlavorSeq, DataFlavorExVector &rDataFlavorExVector)
Definition: transfer.cxx:1228
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
#define ERRCODE_NONE
Definition: errcode.hxx:198
void Read(SvStream &rIStm)
Definition: imap.cxx:955
#define DND_IMAGE_NONE
Definition: transfer.hxx:72
SvStream & ReadGDIMetaFile(SvStream &rIStm, GDIMetaFile &rGDIMetaFile, ImplMetaReadData *pData)
Definition: gdimtf.cxx:2643
#define SAL_INFO(area, stream)
virtual void ObjectReleased()
Definition: transfer.cxx:919
SvStream & WriteSvGlobalName(SvStream &rOStr, const SvGlobalName &rObj)
bool GetBitmapEx(SotClipboardFormatId nFormat, BitmapEx &rBmp)
Definition: transfer.cxx:1536
css::uno::Reference< css::io::XInputStream > GetInputStream(SotClipboardFormatId nFormat, const OUString &rDestDoc)
Definition: transfer.cxx:2095
void SetPrefSize(const Size &rPrefSize)
Definition: bitmapex.hxx:88
bool GetFileList(SotClipboardFormatId nFormat, FileList &rFileList)
Definition: transfer.cxx:2013
tools::Long Height() const
bool IsEmpty() const
Definition: bitmap.hxx:556
sal_uInt64 Tell() const
size_t GetActionSize() const
Definition: gdimtf.cxx:180
Reference< XComponentContext > getProcessComponentContext()
const OUString & GetURL() const
Sequence< sal_Int8 > aSeq
css::uno::Reference< css::datatransfer::XTransferable > mxTransfer
Definition: transfer.hxx:280
css::uno::Any maAny
Definition: transfer.hxx:167
void setHeight(tools::Long nHeight)
static GraphicFilter & GetGraphicFilter()
bool GetTransferableObjectDescriptor(SotClipboardFormatId nFormat, TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:1836
void CopyToSelection(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:281
static TransferableDataHelper CreateFromClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard)
Definition: transfer.cxx:2143
SotClipboardFormatId mnSotId
void SetCompressMode(SvStreamCompressFlags nNewMode)
void dispose()
bool Read(SvStream &rIStm, SotClipboardFormatId nFormat)
Definition: inetimg.cxx:58
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1866
bool SetAny(const css::uno::Any &rAny)
Definition: transfer.cxx:646
void writeGraphic(const Graphic &rGraphic)
BaseContainerNodeSharedPtr & mrParent
bool SetString(const OUString &rString, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:653
aStr
void Write(SvStream &rOStm, SotClipboardFormatId nFormat) const
Definition: inetimg.cxx:28
static OUString ImplGetParameterString(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:112
css::uno::Sequence< sal_Int8 > GetSequence(SotClipboardFormatId nFormat, const OUString &rDestDoc)
Definition: transfer.cxx:2054
bool MakeId(const OUString &rId)
static TransferableDataHelper CreateFromSelection(vcl::Window *pWindow)
Definition: transfer.cxx:2181
virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:286
rtl::Reference< TransferableClipboardNotifier > mxClipboardListener
Definition: transfer.cxx:1136
bool SetGDIMetaFile(const GDIMetaFile &rMtf)
Definition: transfer.cxx:717
const void * GetData()
virtual bool GetData(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc)=0
#define DND_POINTER_NONE
Definition: transfer.hxx:71
static bool GetFormatDataFlavor(SotClipboardFormatId nFormat, css::datatransfer::DataFlavor &rFlavor)
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: transfer.cxx:474