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