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