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  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.Seek( STREAM_SEEK_TO_END ) );
868 
869  return maAny.hasValue();
870 }
871 
872 
873 bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
874 {
875  tools::SvRef<SotStorageStream> xStm( new SotStorageStream( 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<SotStorageStream>&, 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 {
982  DBG_ASSERT( pWindow, "Window pointer is NULL" );
983  Reference< XClipboard > xSelection;
984 
985  if( pWindow )
986  xSelection = pWindow->GetPrimarySelection();
987 
988  CopyToSelection(xSelection);
989 }
990 
991 void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
992 
993 {
994  DBG_ASSERT( pWindow, "Window pointer is NULL" );
995  Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
996 
997  if( !xDragSource.is() )
998  return;
999 
1000  /*
1001  * #96792# release mouse before actually starting DnD.
1002  * This is necessary for the X11 DnD implementation to work.
1003  */
1004  if( pWindow->IsMouseCaptured() )
1005  pWindow->ReleaseMouse();
1006 
1007  const Point aPt( pWindow->GetPointerPosPixel() );
1008 
1009  // On macOS we are forced to execute 'startDrag' synchronously
1010  // contrary to the XDragSource interface specification because
1011  // we can receive drag events from the system only in the main
1012  // thread
1013 #if !defined(MACOSX)
1014  SolarMutexReleaser aReleaser;
1015 #endif
1016 
1017  try
1018  {
1019  DragGestureEvent aEvt;
1020  aEvt.DragAction = DNDConstants::ACTION_COPY;
1021  aEvt.DragOriginX = aPt.X();
1022  aEvt.DragOriginY = aPt.Y();
1023  aEvt.DragSource = xDragSource;
1024 
1025  xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
1026  }
1027  catch( const css::uno::Exception& )
1028  {
1029  }
1030 }
1031 
1033 {
1034  DBG_ASSERT( pWindow, "Window pointer is NULL" );
1035  Reference< XClipboard > xSelection( pWindow->GetPrimarySelection() );
1036 
1037  if( xSelection.is() )
1038  xSelection->setContents( nullptr, nullptr );
1039 }
1040 
1041 namespace
1042 {
1043  class theTransferableHelperUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theTransferableHelperUnoTunnelId > {};
1044 }
1045 
1047 {
1048  return theTransferableHelperUnoTunnelId::get().getSeq();
1049 }
1050 
1051 namespace {
1052 
1053 class TransferableClipboardNotifier : public ::cppu::WeakImplHelper< XClipboardListener >
1054 {
1055 private:
1056  ::osl::Mutex& mrMutex;
1057  Reference< XClipboardNotifier > mxNotifier;
1059 
1060 protected:
1061  // XClipboardListener
1062  virtual void SAL_CALL changedContents( const clipboard::ClipboardEvent& event ) override;
1063 
1064  // XEventListener
1065  virtual void SAL_CALL disposing( const EventObject& Source ) override;
1066 
1067 public:
1068  TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex );
1069 
1071  bool isListening() const { return mpListener != nullptr; }
1072 
1074  void dispose();
1075 };
1076 
1077 }
1078 
1079 TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
1080  :mrMutex( _rMutex )
1081  ,mxNotifier( _rxClipboard, UNO_QUERY )
1082  ,mpListener( &_rListener )
1083 {
1084  osl_atomic_increment( &m_refCount );
1085  {
1086  if ( mxNotifier.is() )
1087  mxNotifier->addClipboardListener( this );
1088  else
1089  // born dead
1090  mpListener = nullptr;
1091  }
1092  osl_atomic_decrement( &m_refCount );
1093 }
1094 
1095 
1096 void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
1097 {
1098  SolarMutexGuard aSolarGuard;
1099  // the SolarMutex here is necessary, since
1100  // - we cannot call mpListener without our own mutex locked
1101  // - Rebind respectively InitFormats (called by Rebind) will
1102  // try to lock the SolarMutex, too
1103  ::osl::MutexGuard aGuard( mrMutex );
1104  if( mpListener )
1105  mpListener->Rebind( event.Contents );
1106 }
1107 
1108 
1109 void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
1110 {
1111  // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1112  dispose();
1113 }
1114 
1115 
1116 void TransferableClipboardNotifier::dispose()
1117 {
1118  ::osl::MutexGuard aGuard( mrMutex );
1119 
1120  Reference< XClipboardListener > xKeepMeAlive( this );
1121 
1122  if ( mxNotifier.is() )
1123  mxNotifier->removeClipboardListener( this );
1124  mxNotifier.clear();
1125 
1126  mpListener = nullptr;
1127 }
1128 
1130 {
1131  ::osl::Mutex maMutex;
1133 
1135  {
1136  }
1137 };
1138 
1140  : mxObjDesc(new TransferableObjectDescriptor)
1141  , mxImpl(new TransferableDataHelper_Impl)
1142 {
1143 }
1144 
1145 TransferableDataHelper::TransferableDataHelper(const Reference< css::datatransfer::XTransferable >& rxTransferable)
1146  : mxTransfer(rxTransferable)
1147  , mxObjDesc(new TransferableObjectDescriptor)
1148  , mxImpl(new TransferableDataHelper_Impl)
1149 {
1150  InitFormats();
1151 }
1152 
1154  : mxTransfer(rDataHelper.mxTransfer)
1155  , mxClipboard(rDataHelper.mxClipboard)
1156  , maFormats(rDataHelper.maFormats)
1157  , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
1158  , mxImpl(new TransferableDataHelper_Impl)
1159 {
1160 }
1161 
1163  : mxTransfer(std::move(rDataHelper.mxTransfer))
1164  , mxClipboard(std::move(rDataHelper.mxClipboard))
1165  , maFormats(std::move(rDataHelper.maFormats))
1166  , mxObjDesc(std::move(rDataHelper.mxObjDesc))
1167  , mxImpl(new TransferableDataHelper_Impl)
1168 {
1169 }
1170 
1172 {
1173  if ( this != &rDataHelper )
1174  {
1175  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1176 
1177  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1178 
1179  if (bWasClipboardListening)
1181 
1182  mxTransfer = rDataHelper.mxTransfer;
1183  maFormats = rDataHelper.maFormats;
1184  mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
1185  mxClipboard = rDataHelper.mxClipboard;
1186 
1187  if (bWasClipboardListening)
1189  }
1190 
1191  return *this;
1192 }
1193 
1195 {
1196  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1197 
1198  const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1199 
1200  if (bWasClipboardListening)
1202 
1203  mxTransfer = std::move(rDataHelper.mxTransfer);
1204  maFormats = std::move(rDataHelper.maFormats);
1205  mxObjDesc = std::move(rDataHelper.mxObjDesc);
1206  mxClipboard = std::move(rDataHelper.mxClipboard);
1207 
1208  if (bWasClipboardListening)
1210 
1211  return *this;
1212 }
1213 
1215 {
1217  {
1218  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1219  maFormats.clear();
1220  mxObjDesc.reset();
1221  }
1222 }
1223 
1224 void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
1225  DataFlavorExVector& rDataFlavorExVector )
1226 {
1227  try
1228  {
1230  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
1231  DataFlavorEx aFlavorEx;
1232  const OUString aCharsetStr( "charset" );
1233 
1234 
1235  for (auto const& rFlavor : rDataFlavorSeq)
1236  {
1237  Reference< XMimeContentType > xMimeType;
1238 
1239  try
1240  {
1241  if( !rFlavor.MimeType.isEmpty() )
1242  xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
1243  }
1244  catch( const css::uno::Exception& )
1245  {
1246  }
1247 
1248  aFlavorEx.MimeType = rFlavor.MimeType;
1249  aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
1250  aFlavorEx.DataType = rFlavor.DataType;
1251  aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
1252 
1253  rDataFlavorExVector.push_back( aFlavorEx );
1254 
1255  // add additional formats for special mime types
1256  if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId || SotClipboardFormatId::JPEG == aFlavorEx.mnSotId)
1257  {
1258  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
1259  {
1260  aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
1261  rDataFlavorExVector.push_back( aFlavorEx );
1262  }
1263  }
1264  else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
1265  {
1266  if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
1267  {
1268  aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
1269  rDataFlavorExVector.push_back( aFlavorEx );
1270  }
1271  }
1272  else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
1273  {
1274  // #104735# HTML_SIMPLE may also be inserted without comments
1275  aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
1276  rDataFlavorExVector.push_back( aFlavorEx );
1277  }
1278  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
1279  {
1280  // add, if it is a UTF-8 byte buffer
1281  if( xMimeType->hasParameter( aCharsetStr ) )
1282  {
1283  if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
1284  xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
1285  {
1286  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
1287 
1288  }
1289  }
1290  }
1291  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
1292  {
1293  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
1294  }
1295  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
1296  {
1297  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
1298  }
1299  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
1300 
1301  {
1302  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
1303  }
1304  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
1305  {
1306  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
1307  }
1308  else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
1309  {
1310  rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
1311  }
1312  }
1313  }
1314  catch( const css::uno::Exception& )
1315  {
1316  }
1317 }
1318 
1320 {
1321  SolarMutexGuard aSolarGuard;
1322  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1323 
1324  maFormats.clear();
1326 
1327  if( !mxTransfer.is() )
1328  return;
1329 
1331 
1332  for (auto const& format : maFormats)
1333  {
1334  if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
1335  {
1337  break;
1338  }
1339  }
1340 }
1341 
1342 
1344 {
1345  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1346  return std::any_of(maFormats.begin(), maFormats.end(),
1347  [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
1348 }
1349 
1350 bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
1351 {
1352  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1353  for (auto const& format : maFormats)
1354  {
1355  if( TransferableDataHelper::IsEqual( rFlavor, format ) )
1356  return true;
1357  }
1358 
1359  return false;
1360 }
1361 
1363 {
1364  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1365  return maFormats.size();
1366 }
1367 
1369 {
1370  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1371  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1372  return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
1373 }
1374 
1375 DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
1376 {
1377  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1378  DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1379 
1380  DataFlavor aRet;
1381 
1382  if (nFormat < maFormats.size())
1383  aRet = maFormats[nFormat];
1384 
1385  return aRet;
1386 }
1387 
1388 
1389 Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
1390 {
1391  Reference< XTransferable > xRet;
1392 
1393  if( mxTransfer.is() )
1394  {
1395  try
1396  {
1397  xRet = mxTransfer;
1398 
1399  // do a dummy call to check, if this interface is valid (nasty)
1400  xRet->getTransferDataFlavors();
1401 
1402  }
1403  catch( const css::uno::Exception& )
1404  {
1405  xRet.clear();
1406  }
1407  }
1408 
1409  return xRet;
1410 }
1411 
1412 
1413 Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
1414 {
1415  Any aReturn;
1416 
1417  DataFlavor aFlavor;
1418  if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
1419  aReturn = GetAny(aFlavor, rDestDoc);
1420 
1421  return aReturn;
1422 }
1423 
1424 Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
1425 {
1426  ::osl::MutexGuard aGuard(mxImpl->maMutex);
1427  Any aRet;
1428 
1429  try
1430  {
1431  if( mxTransfer.is() )
1432  {
1433  const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
1434 
1435  Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
1436 
1437  if( nRequestFormat != SotClipboardFormatId::NONE )
1438  {
1439  // try to get alien format first
1440  for (auto const& format : maFormats)
1441  {
1442  if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
1443  {
1444 // tdf#133365: only release solar mutex on Windows
1445 #ifdef _WIN32
1446  // tdf#133527: first, make sure that we actually hold the mutex
1447  SolarMutexGuard g;
1448  // Our own thread may handle the nested IDataObject::GetData call,
1449  // and try to acquire solar mutex
1451 #endif // _WIN32
1452 
1453  if (xTransfer2.is())
1454  aRet = xTransfer2->getTransferData2(format, rDestDoc);
1455  else
1456  aRet = mxTransfer->getTransferData(format);
1457  }
1458 
1459  if( aRet.hasValue() )
1460  break;
1461  }
1462  }
1463 
1464  if( !aRet.hasValue() )
1465  {
1466 // tdf#133365: only release solar mutex on Windows
1467 #ifdef _WIN32
1468  // tdf#133527: first, make sure that we actually hold the mutex
1469  SolarMutexGuard g;
1470  // Our own thread may handle the nested IDataObject::GetData call,
1471  // and try to acquire solar mutex
1473 #endif // _WIN32
1474 
1475  if (xTransfer2.is())
1476  aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
1477  else
1478  aRet = mxTransfer->getTransferData(rFlavor);
1479  }
1480  }
1481  }
1482  catch( const css::uno::Exception& )
1483  {
1484  }
1485 
1486  return aRet;
1487 }
1488 
1489 
1491 {
1492  DataFlavor aFlavor;
1493  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
1494 }
1495 
1496 
1497 bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr )
1498 {
1499  Any aAny = GetAny(rFlavor, OUString());
1500  bool bRet = false;
1501 
1502  if( aAny.hasValue() )
1503  {
1504  OUString aOUString;
1506 
1507  if( aAny >>= aOUString )
1508  {
1509  rStr = aOUString;
1510  bRet = true;
1511  }
1512  else if( aAny >>= aSeq )
1513  {
1514 
1515  const char* pChars = reinterpret_cast< const char* >( aSeq.getConstArray() );
1516  sal_Int32 nLen = aSeq.getLength();
1517 
1518  //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
1519  //DVO 2002-05-27: strip _all_ trailing zeros
1520  while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
1521  --nLen;
1522 
1523  rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
1524  bRet = true;
1525  }
1526  }
1527 
1528  return bRet;
1529 }
1530 
1531 
1533 {
1534  if(SotClipboardFormatId::BITMAP == nFormat)
1535  {
1536  // try to get PNG first
1537  DataFlavor aFlavor;
1538 
1539  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1540  {
1541  if(GetBitmapEx(aFlavor, rBmpEx))
1542  {
1543  return true;
1544  }
1545  }
1546 
1547  // then JPEG
1548  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor))
1549  {
1550  if(GetBitmapEx(aFlavor, rBmpEx))
1551  {
1552  return true;
1553  }
1554  }
1555  }
1556 
1557  DataFlavor aFlavor;
1558  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
1559 }
1560 
1561 
1562 bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx )
1563 {
1565  DataFlavor aSubstFlavor;
1566  bool bRet(GetSotStorageStream(rFlavor, xStm));
1567  bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
1568  bool bSuppressJPEG(false);
1569 
1570  if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
1571  {
1572  // when no direct success, try if PNG is available
1573  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1574  bSuppressJPEG = bRet;
1575  }
1576 
1577  if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
1578  {
1579  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1580  bSuppressPNG = bRet;
1581  }
1582 
1583  if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
1584  {
1585  // when no direct success, try if BMP is available
1586  bRet = GetSotStorageStream(aSubstFlavor, xStm);
1587  bSuppressPNG = bRet;
1588  bSuppressJPEG = bRet;
1589  }
1590 
1591  if(bRet)
1592  {
1593  if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
1594  {
1595  // it's a PNG, import to BitmapEx
1596  vcl::PNGReader aPNGReader(*xStm);
1597 
1598  rBmpEx = aPNGReader.Read();
1599  }
1600  else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
1601  {
1602  // it's a JPEG, import to BitmapEx
1604  Graphic aGraphic;
1605  if (rFilter.ImportGraphic(aGraphic, "", *xStm) == ERRCODE_NONE)
1606  rBmpEx = aGraphic.GetBitmapEx();
1607  }
1608 
1609  if(rBmpEx.IsEmpty())
1610  {
1611  Bitmap aBitmap;
1612  AlphaMask aMask;
1613 
1614  // explicitly use Bitmap::Read with bFileHeader = sal_True
1615  // #i124085# keep DIBV5 for read from clipboard, but should not happen
1616  ReadDIBV5(aBitmap, aMask, *xStm);
1617 
1618  if(aMask.GetBitmap().IsEmpty())
1619  {
1620  rBmpEx = aBitmap;
1621  }
1622  else
1623  {
1624  rBmpEx = BitmapEx(aBitmap, aMask);
1625  }
1626  }
1627 
1628  bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
1629 
1630  /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
1631  problem is, that some graphics are inserted much too big because the nXPelsPerMeter
1632  and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
1633  Due to this reason the following code assumes that bitmaps with a logical size
1634  greater than 50 cm aren't having the correct mapmode set.
1635 
1636  The following code should be removed if DDBs and DIBs are supported via clipboard
1637  properly.
1638  */
1639  if(bRet)
1640  {
1641  const MapMode aMapMode(rBmpEx.GetPrefMapMode());
1642 
1643  if(MapUnit::MapPixel != aMapMode.GetMapUnit())
1644  {
1645  const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
1646 
1647  // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
1648  // the described 50 cm (which is 50000 100th mm)
1649  if((aSize.Width() > 50000) || (aSize.Height() > 50000))
1650  {
1651  rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
1652 
1653  // #i122388# also adapt size by applying the mew MapMode
1654  const Size aNewSize(OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel)));
1655  rBmpEx.SetPrefSize(aNewSize);
1656  }
1657  }
1658  }
1659  }
1660 
1661  return bRet;
1662 }
1663 
1664 
1666 {
1667  DataFlavor aFlavor;
1668  return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
1669  GetGDIMetaFile(aFlavor, rMtf) &&
1670  (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
1671 }
1672 
1673 
1674 bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf )
1675 {
1677  DataFlavor aSubstFlavor;
1678  bool bRet = false;
1679 
1680  if( GetSotStorageStream( rFlavor, xStm ) )
1681  {
1682  ReadGDIMetaFile( *xStm, rMtf );
1683  bRet = ( xStm->GetError() == ERRCODE_NONE );
1684  }
1685 
1686  if( !bRet &&
1687  HasFormat( SotClipboardFormatId::EMF ) &&
1688  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
1689  GetSotStorageStream( aSubstFlavor, xStm ) )
1690  {
1691  Graphic aGraphic;
1692 
1693  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1694  {
1695  rMtf = aGraphic.GetGDIMetaFile();
1696  bRet = true;
1697  }
1698  }
1699 
1700  if( !bRet &&
1701  HasFormat( SotClipboardFormatId::WMF ) &&
1702  SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
1703  GetSotStorageStream( aSubstFlavor, xStm ) )
1704  {
1705  Graphic aGraphic;
1706 
1707  if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1708  {
1709  rMtf = aGraphic.GetGDIMetaFile();
1710  bRet = true;
1711  }
1712  }
1713 
1714  return bRet;
1715 }
1716 
1717 
1719 {
1720  if(SotClipboardFormatId::BITMAP == nFormat)
1721  {
1722  // try to get PNG first
1723  DataFlavor aFlavor;
1724 
1725  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1726  {
1727  if(GetGraphic(aFlavor, rGraphic))
1728  {
1729  return true;
1730  }
1731  }
1732  }
1733 
1734  DataFlavor aFlavor;
1735  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
1736 }
1737 
1738 
1739 bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic )
1740 {
1741  DataFlavor aFlavor;
1742  bool bRet = false;
1743 
1744  if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
1745  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1746  {
1747  // try to get PNG first
1748  BitmapEx aBmpEx;
1749 
1750  bRet = GetBitmapEx( aFlavor, aBmpEx );
1751  if( bRet )
1752  rGraphic = aBmpEx;
1753  }
1754  else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
1755  TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1756  {
1757  Graphic aGraphic;
1759  if (GetSotStorageStream(rFlavor, xStm))
1760  {
1761  if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
1762  {
1763  rGraphic = aGraphic;
1764  bRet = true;
1765  }
1766  }
1767  }
1768  else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1769  {
1770  BitmapEx aBitmapEx;
1771 
1772  bRet = GetBitmapEx(aFlavor, aBitmapEx);
1773  if (bRet)
1774  rGraphic = aBitmapEx;
1775  }
1776  else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
1777  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1778  {
1779  BitmapEx aBmpEx;
1780 
1781  bRet = GetBitmapEx( aFlavor, aBmpEx );
1782  if( bRet )
1783  rGraphic = aBmpEx;
1784  }
1785  else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
1786  TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1787  {
1788  GDIMetaFile aMtf;
1789 
1790  bRet = GetGDIMetaFile( aFlavor, aMtf );
1791  if( bRet )
1792  rGraphic = aMtf;
1793  }
1794  else
1795  {
1797 
1798  if( GetSotStorageStream( rFlavor, xStm ) )
1799  {
1800  ReadGraphic( *xStm, rGraphic );
1801  bRet = ( xStm->GetError() == ERRCODE_NONE );
1802  }
1803  }
1804 
1805  return bRet;
1806 }
1807 
1808 
1810 {
1811  DataFlavor aFlavor;
1812  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
1813 }
1814 
1815 
1816 bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap )
1817 {
1819  bool bRet = GetSotStorageStream( rFlavor, xStm );
1820 
1821  if( bRet )
1822  {
1823  rIMap.Read( *xStm );
1824  bRet = ( xStm->GetError() == ERRCODE_NONE );
1825  }
1826 
1827  return bRet;
1828 }
1829 
1830 
1832 {
1833  DataFlavor aFlavor;
1834  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
1835 }
1836 
1837 
1839 {
1840  rDesc = *mxObjDesc;
1841  return true;
1842 }
1843 
1844 
1846 {
1847  DataFlavor aFlavor;
1848  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
1849 }
1850 
1851 
1852 bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk )
1853 {
1854  bool bRet = false;
1855  if( HasFormat( rFlavor ))
1856  {
1857  const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
1858  switch( nFormat )
1859  {
1860  case SotClipboardFormatId::SOLK:
1861  case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
1862  {
1863  OUString aString;
1864  if( GetString( rFlavor, aString ) )
1865  {
1866  if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
1867  {
1868  rBmk = INetBookmark( aString, aString );
1869  bRet = true;
1870  }
1871  else
1872  {
1873  OUString aURL, aDesc;
1874  sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
1875 
1876  if( !nLen && aString[ 0 ] != '0' )
1877  {
1878  SAL_INFO( "svtools", "SOLK: 1. len=0" );
1879  }
1880  if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
1881  {
1882  SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
1883  }
1884  aURL = aString.copy( nStart + 1, nLen );
1885 
1886  aString = aString.replaceAt( 0, nStart + 1 + nLen, "" );
1887  nStart = aString.indexOf( '@' );
1888  nLen = aString.toInt32();
1889 
1890  if( !nLen && aString[ 0 ] != '0' )
1891  {
1892  SAL_INFO( "svtools", "SOLK: 2. len=0" );
1893  }
1894  if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
1895  {
1896  SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
1897  }
1898  aDesc = aString.copy( nStart+1, nLen );
1899 
1900  rBmk = INetBookmark( aURL, aDesc );
1901  bRet = true;
1902  }
1903  }
1904  }
1905  break;
1906 
1907  case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1908  {
1909  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1910 
1911  if (2048 == aSeq.getLength())
1912  {
1913  const char* p1 = reinterpret_cast< const char* >( aSeq.getConstArray() );
1914  const char* p2 = reinterpret_cast< const char* >( aSeq.getConstArray() ) + 1024;
1915  rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
1916  OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
1917  bRet = true;
1918  }
1919  }
1920  break;
1921 
1922 #ifdef _WIN32
1923  case SotClipboardFormatId::FILEGRPDESCRIPTOR:
1924  {
1925  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1926 
1927  if (aSeq.getLength())
1928  {
1929  FILEGROUPDESCRIPTOR const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR const *>(aSeq.getConstArray());
1930 
1931  if( pFDesc->cItems )
1932  {
1933  OString aDesc( pFDesc->fgd[ 0 ].cFileName );
1934  rtl_TextEncoding eTextEncoding = osl_getThreadTextEncoding();
1935 
1936  if( ( aDesc.getLength() > 4 ) && aDesc.copy(aDesc.getLength() - 4).equalsIgnoreAsciiCase(".URL") )
1937  {
1938  std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( OStringToOUString(aDesc, eTextEncoding) ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1939  StreamMode::STD_READ ));
1940 
1941  if( !pStream || pStream->GetError() )
1942  {
1943  DataFlavor aFileContentFlavor;
1944 
1945  aSeq.realloc( 0 );
1946  pStream.reset();
1947 
1948  if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
1949  {
1950  aSeq = GetSequence(aFileContentFlavor, OUString());
1951  if (aSeq.getLength())
1952  pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
1953  }
1954  }
1955 
1956  if( pStream )
1957  {
1958  OString aLine;
1959  bool bSttFnd = false;
1960 
1961  while( pStream->ReadLine( aLine ) )
1962  {
1963  if (aLine.equalsIgnoreAsciiCase("[InternetShortcut]"))
1964  bSttFnd = true;
1965  else if (bSttFnd && aLine.copy(0, 4).equalsIgnoreAsciiCase("URL="))
1966  {
1967  rBmk = INetBookmark( OStringToOUString(aLine.copy(4), eTextEncoding),
1968  OStringToOUString(aDesc.copy(0, aDesc.getLength() - 4), eTextEncoding) );
1969  bRet = true;
1970  break;
1971  }
1972  }
1973  }
1974  }
1975  }
1976  }
1977  }
1978  break;
1979 #endif
1980  default: break;
1981  }
1982  }
1983  return bRet;
1984 }
1985 
1986 
1988  INetImage& rINtImg )
1989 {
1990  DataFlavor aFlavor;
1991  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
1992 }
1993 
1994 
1996  const css::datatransfer::DataFlavor& rFlavor,
1997  INetImage& rINtImg )
1998 {
2000  bool bRet = GetSotStorageStream( rFlavor, xStm );
2001 
2002  if( bRet )
2003  bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
2004  return bRet;
2005 }
2006 
2007 
2009  FileList& rFileList )
2010 {
2011  DataFlavor aFlavor;
2012  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
2013 }
2014 
2015 
2017 {
2019  bool bRet = false;
2020 
2021  for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
2022  {
2023  if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
2024  {
2025  const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
2026 
2027  if( GetSotStorageStream( aFlavor, xStm ) )
2028  {
2029  if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
2030  {
2031  OString aDiskString;
2032 
2033  while( xStm->ReadLine( aDiskString ) )
2034  if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
2035  rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
2036 
2037  bRet = true;
2038  }
2039  else
2040  bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
2041  }
2042  }
2043  }
2044 
2045  return bRet;
2046 }
2047 
2048 
2049 Sequence<sal_Int8> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat, const OUString& rDestDoc )
2050 {
2051  DataFlavor aFlavor;
2052  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2053  return Sequence<sal_Int8>();
2054 
2055  return GetSequence(aFlavor, rDestDoc);
2056 }
2057 
2058 Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc )
2059 {
2060  const Any aAny = GetAny(rFlavor, rDestDoc);
2061  Sequence<sal_Int8> aSeq;
2062  if (aAny.hasValue())
2063  aAny >>= aSeq;
2064 
2065  return aSeq;
2066 }
2067 
2068 
2070 {
2071  DataFlavor aFlavor;
2072  return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
2073 }
2074 
2075 
2076 bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotStorageStream>& rxStream )
2077 {
2078  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
2079 
2080  if (aSeq.hasElements())
2081  {
2082  rxStream = new SotStorageStream( "" );
2083  rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
2084  rxStream->Seek( 0 );
2085  }
2086 
2087  return aSeq.hasElements();
2088 }
2089 
2091 {
2092  DataFlavor aFlavor;
2093  if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2094  return Reference<XInputStream>();
2095 
2096  return GetInputStream(aFlavor, rDestDoc);
2097 }
2098 
2099 Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc )
2100 {
2101  Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
2102 
2103  if (!aSeq.hasElements())
2104  return Reference<XInputStream>();
2105 
2107  return xStream;
2108 }
2109 
2110 void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
2111 {
2112  mxTransfer = _rxNewContent;
2113  InitFormats();
2114 }
2115 
2117 {
2118  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2119 
2121 
2122  mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
2123 
2124  return mxImpl->mxClipboardListener->isListening();
2125 }
2126 
2128 {
2129  ::osl::MutexGuard aGuard(mxImpl->maMutex);
2130 
2131  if (mxImpl->mxClipboardListener.is())
2132  {
2133  mxImpl->mxClipboardListener->dispose();
2134  mxImpl->mxClipboardListener.clear();
2135  }
2136 }
2137 
2138 TransferableDataHelper TransferableDataHelper::CreateFromClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& rClipboard)
2139 {
2141 
2142  if( rClipboard.is() )
2143  {
2144  try
2145  {
2146  Reference< XTransferable > xTransferable( rClipboard->getContents() );
2147 
2148  if( xTransferable.is() )
2149  {
2150  aRet = TransferableDataHelper( xTransferable );
2151  // also copy the clipboard
2152  aRet.mxClipboard = rClipboard;
2153  }
2154  }
2155  catch( const css::uno::Exception& )
2156  {
2157  }
2158  }
2159 
2160  return aRet;
2161 }
2162 
2164 {
2165  DBG_ASSERT( pWindow, "Window pointer is NULL" );
2166 
2167  Reference< XClipboard > xClipboard;
2168 
2169  if( pWindow )
2170  xClipboard = pWindow->GetClipboard();
2171 
2172  return CreateFromClipboard(xClipboard);
2173 }
2174 
2175 
2177 {
2178  DBG_ASSERT( pWindow, "Window pointer is NULL" );
2179 
2180  Reference< XClipboard > xSelection;
2182 
2183  if( pWindow )
2184  xSelection = pWindow->GetPrimarySelection();
2185 
2186  if( xSelection.is() )
2187  {
2188  SolarMutexReleaser aReleaser;
2189 
2190  try
2191  {
2192  Reference< XTransferable > xTransferable( xSelection->getContents() );
2193 
2194  if( xTransferable.is() )
2195  {
2196  aRet = TransferableDataHelper( xTransferable );
2197  aRet.mxClipboard = xSelection;
2198  }
2199  }
2200  catch( const css::uno::Exception& )
2201  {
2202  }
2203  }
2204 
2205  return aRet;
2206 }
2207 
2208 
2209 bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
2210  const css::datatransfer::DataFlavor& rRequestFlavor )
2211 {
2213  bool bRet = false;
2214 
2215  try
2216  {
2217  Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
2218 
2219  Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
2220  Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
2221 
2222  if( xRequestType1.is() && xRequestType2.is() )
2223  {
2224  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
2225  {
2226  if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
2227  {
2228  // special handling for text/plain media types
2229  const OUString aCharsetString( "charset" );
2230 
2231  if( !xRequestType2->hasParameter( aCharsetString ) ||
2232  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
2233  xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
2234  {
2235  bRet = true;
2236  }
2237  }
2238  else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
2239  {
2240  // special handling for application/x-openoffice media types
2241  const OUString aFormatString( "windows_formatname" );
2242 
2243  if( xRequestType1->hasParameter( aFormatString ) &&
2244  xRequestType2->hasParameter( aFormatString ) &&
2245  xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
2246  {
2247  bRet = true;
2248  }
2249  }
2250  else
2251  bRet = true;
2252  }
2253  }
2254  }
2255  catch( const css::uno::Exception& )
2256  {
2257  bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
2258  }
2259 
2260  return bRet;
2261 }
2262 
2263 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long Width() const
bool GetGraphic(SotClipboardFormatId nFormat, Graphic &rGraphic)
Definition: transfer.cxx:1718
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:859
css::uno::Reference< css::datatransfer::dnd::XDragSource > GetDragSource()
Definition: mouse.cxx:719
Point GetPointerPosPixel()
Definition: mouse.cxx:550
VCL_DLLPRIVATE void ImplFlush()
Definition: transfer.cxx: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:1413
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:523
const MapMode & GetPrefMapMode() const
Definition: bitmapex.hxx:89
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1675
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:3406
OUString maLastFormat
Definition: transfer.hxx:167
Bitmap const & GetBitmap() const
Definition: alpha.cxx:73
void Rebind(const css::uno::Reference< css::datatransfer::XTransferable > &_rxNewData)
Definition: transfer.cxx:2110
::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:903
SotClipboardFormatId GetFormat(sal_uInt32 nFormat) const
Definition: transfer.cxx:1368
virtual void DragFinished(sal_Int8 nDropAction)
Definition: transfer.cxx:910
bool GetINetBookmark(SotClipboardFormatId nFormat, INetBookmark &rBmk)
Definition: transfer.cxx:1845
virtual sal_Bool SAL_CALL isComplex() override
Definition: transfer.cxx:402
bool HasFormat(SotClipboardFormatId nFormat) const
Definition: transfer.cxx:1343
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: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:1415
css::uno::Reference< css::datatransfer::clipboard::XClipboard > GetPrimarySelection()
Definition: window.cxx:3415
IntrinsicAnimationEventHandlerSharedPtr mpListener
SvStream & WriteUniOrByteString(const OUString &rStr, rtl_TextEncoding eDestCharSet)
static TransferableDataHelper CreateFromSystemClipboard(vcl::Window *pWindow)
Definition: transfer.cxx:2163
const GDIMetaFile & GetGDIMetaFile() const
Definition: graph.cxx:335
SvStream & WriteUInt32(sal_uInt32 nUInt32)
virtual css::uno::Any SAL_CALL getTransferData2(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc) override
Definition: transfer.cxx:290
TransferableDataHelper & operator=(const TransferableDataHelper &rDataHelper)
Definition: transfer.cxx:1171
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:2209
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:1987
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:1375
int i
TerminateListener(TransferableHelper &rDropTargetHelper)
Definition: transfer.cxx:231
GraphicType GetType() const
Definition: graph.cxx:289
OUString GetHexName() const
#define STREAM_SEEK_TO_BEGIN
css::uno::Reference< css::datatransfer::XTransferable > GetXTransferable() const
Definition: transfer.cxx:1389
virtual void SAL_CALL queryTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:247
bool GetString(SotClipboardFormatId nFormat, OUString &rStr)
Definition: transfer.cxx:1490
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
Definition: transfer.cxx:1046
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:529
#define TOD_SIG1
Definition: transfer.cxx:78
sal_uInt32 GetFormatCount() const
Definition: transfer.cxx:1362
unsigned char sal_Bool
bool Write(SvStream &rStream)
Definition: pngwrite.cxx:708
const OUString & GetDescription() const
void PrepareOLE(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:920
bool IsMouseCaptured() const
Definition: mouse.cxx:469
void StartDrag(vcl::Window *pWindow, sal_Int8 nDragSourceActions)
Definition: transfer.cxx:991
bool ReadDIBV5(Bitmap &rTarget, AlphaMask &rTargetAlpha, SvStream &rIStm)
Definition: dibtools.cxx:1833
static void ClearSelection(vcl::Window *pWindow)
Definition: transfer.cxx:1032
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:325
void CopyToClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
void SetVersion(sal_Int32 n)
void AppendFile(const OUString &rStr)
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx: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:2069
bool GetImageMap(SotClipboardFormatId nFormat, ImageMap &rIMap)
Definition: transfer.cxx:1809
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:1665
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:1224
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
#define ERRCODE_NONE
Definition: errcode.hxx:198
void Read(SvStream &rIStm)
Definition: imap.cxx:955
#define DND_IMAGE_NONE
Definition: transfer.hxx:71
SvStream & ReadGDIMetaFile(SvStream &rIStm, GDIMetaFile &rGDIMetaFile, ImplMetaReadData *pData)
Definition: gdimtf.cxx:2645
#define SAL_INFO(area, stream)
virtual void ObjectReleased()
Definition: transfer.cxx:915
SvStream & WriteSvGlobalName(SvStream &rOStr, const SvGlobalName &rObj)
bool GetBitmapEx(SotClipboardFormatId nFormat, BitmapEx &rBmp)
Definition: transfer.cxx:1532
css::uno::Reference< css::io::XInputStream > GetInputStream(SotClipboardFormatId nFormat, const OUString &rDestDoc)
Definition: transfer.cxx:2090
void SetPrefSize(const Size &rPrefSize)
Definition: bitmapex.hxx:87
bool GetFileList(SotClipboardFormatId nFormat, FileList &rFileList)
Definition: transfer.cxx:2008
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:1831
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:2138
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:2049
bool MakeId(const OUString &rId)
static TransferableDataHelper CreateFromSelection(vcl::Window *pWindow)
Definition: transfer.cxx:2176
virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:285
rtl::Reference< TransferableClipboardNotifier > mxClipboardListener
Definition: transfer.cxx:1132
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