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